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
|
||||
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
intsets, idgen
|
||||
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
TCallingConvention* = enum
|
||||
ccDefault, # proc has no explicit calling convention
|
||||
ccStdCall, # procedure is stdcall
|
||||
ccCDecl, # cdecl
|
||||
|
|
@ -26,12 +26,12 @@ type
|
|||
ccClosure, # proc has a closure
|
||||
ccNoConvention # needed for generating proper C procs sometimes
|
||||
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
|
||||
"closure", "noconv"]
|
||||
|
||||
type
|
||||
type
|
||||
TNodeKind* = enum # order is extremely important, because ranges are used
|
||||
# to check whether a node belongs to a certain class
|
||||
nkNone, # unknown node kind: indicates an error
|
||||
|
|
@ -64,13 +64,13 @@ type
|
|||
# end of atoms
|
||||
nkMetaNode_Obsolete, # difficult to explain; represents itself
|
||||
# (used for macros)
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
# this is used
|
||||
# for transforming ``s.len`` to ``len(s)``
|
||||
|
||||
nkCommand, # a call like ``p 2, 4`` without parenthesis
|
||||
nkCall, # a call like p(x, y) or an operation like +(a, b)
|
||||
nkCallStrLit, # a call with a string literal
|
||||
nkCallStrLit, # a call with a string literal
|
||||
# x"abc" has two sons: nkIdent, nkRStrLit
|
||||
# x"""abc""" has two sons: nkIdent, nkTripleStrLit
|
||||
nkInfix, # a call like (a + b)
|
||||
|
|
@ -126,7 +126,7 @@ type
|
|||
|
||||
nkAsgn, # a = b
|
||||
nkFastAsgn, # internal node for a fast ``a = b``
|
||||
# (no string copy)
|
||||
# (no string copy)
|
||||
nkGenericParams, # generic parameters
|
||||
nkFormalParams, # formal parameters
|
||||
nkOfInherit, # inherited from symbol
|
||||
|
|
@ -192,10 +192,11 @@ type
|
|||
|
||||
nkWith, # distinct with `foo`
|
||||
nkWithout, # distinct without `foo`
|
||||
|
||||
|
||||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
nkTupleClassTy, # tuple type class
|
||||
nkTypeClassTy, # user-defined type class
|
||||
nkStaticTy, # ``static[T]``
|
||||
nkRecList, # list of object parts
|
||||
|
|
@ -226,7 +227,7 @@ type
|
|||
TSymFlag* = enum # already 32 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
# for symbol file generation; such symbols should always
|
||||
# be written into the ROD file
|
||||
sfGlobal, # symbol is at global scope
|
||||
|
|
@ -284,9 +285,9 @@ const
|
|||
|
||||
sfAnon* = sfDiscardable
|
||||
# symbol name that was generated by the compiler
|
||||
# the compiler will avoid printing such names
|
||||
# the compiler will avoid printing such names
|
||||
# in user messages.
|
||||
|
||||
|
||||
sfNoForward* = sfRegister
|
||||
# forward declarations are not required (per module)
|
||||
|
||||
|
|
@ -300,7 +301,7 @@ const
|
|||
# getting ready for the future expr/stmt merge
|
||||
nkWhen* = nkWhenStmt
|
||||
nkWhenExpr* = nkWhenStmt
|
||||
nkEffectList* = nkArgList
|
||||
nkEffectList* = nkArgList
|
||||
# hacks ahead: an nkEffectList is a node with 4 children:
|
||||
exceptionEffects* = 0 # exceptions at position 0
|
||||
usesEffects* = 1 # read effects at position 1
|
||||
|
|
@ -321,7 +322,7 @@ type
|
|||
# unless this is an instance of a generic alias type.
|
||||
# then realInstance will be the tyGenericInst of the
|
||||
# completely (recursively) resolved alias.
|
||||
|
||||
|
||||
tyGenericParam, # ``a`` in the above patterns
|
||||
tyDistinct,
|
||||
tyEnum,
|
||||
|
|
@ -340,14 +341,14 @@ type
|
|||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyIter, # unused
|
||||
tyProxy # used as errornous type (for idetools)
|
||||
|
||||
|
||||
tyBuiltInTypeClass #\
|
||||
# Type such as the catch-all object, tuple, seq, etc
|
||||
|
||||
|
||||
tyUserTypeClass #\
|
||||
# the body of a user-defined type class
|
||||
|
||||
|
|
@ -357,24 +358,24 @@ type
|
|||
# tyGenericInst represents concrete types, while
|
||||
# this is still a "generic param" that will bind types
|
||||
# and resolves them during sigmatch and instantiation.
|
||||
|
||||
|
||||
tyCompositeTypeClass #\
|
||||
# Type such as seq[Number]
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# sons[0]: the original expression used by the user.
|
||||
# sons[1]: fully expanded and instantiated meta type
|
||||
# (potentially following aliases)
|
||||
|
||||
|
||||
tyAnd, tyOr, tyNot #\
|
||||
# boolean type classes such as `string|int`,`not seq`,
|
||||
# `Sortable and Enumable`, etc
|
||||
|
||||
|
||||
tyAnything #\
|
||||
# a type class matching any type
|
||||
|
||||
|
||||
tyStatic #\
|
||||
# a value known at compile type (the underlying type is .base)
|
||||
|
||||
|
||||
tyFromExpr #\
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the expression is stored in t.n)
|
||||
|
|
@ -390,7 +391,7 @@ type
|
|||
# sons[0]: type of containing object or tuple
|
||||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
|
|
@ -408,7 +409,7 @@ const
|
|||
tyAnd, tyOr, tyNot, tyAnything}
|
||||
|
||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
|
||||
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
||||
|
|
@ -429,7 +430,7 @@ type
|
|||
nfExprCall # this is an attempt to call a regular expression
|
||||
nfIsRef # this node is a 'ref' node; used for the VM
|
||||
nfIsCursor # this node is attached a cursor; used for idetools
|
||||
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
|
|
@ -448,7 +449,7 @@ type
|
|||
# proc foo(L: static[int]): array[L, int]
|
||||
# can be attached to ranges to indicate that the range
|
||||
# depends on unresolved static params.
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
tfByCopy, # pass object/tuple by copy (C backend)
|
||||
|
|
@ -456,9 +457,9 @@ type
|
|||
tfIterator, # type is really an iterator, not a tyProc
|
||||
tfShared, # type is 'shared'
|
||||
tfNotNil, # type cannot be 'nil'
|
||||
|
||||
|
||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||
# other type so that it requires inititalization
|
||||
# other type so that it requires initalization
|
||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||
# or other type classes
|
||||
|
|
@ -520,7 +521,7 @@ const
|
|||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
skError* = skUnknown
|
||||
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
|
||||
|
||||
|
|
@ -531,29 +532,29 @@ type
|
|||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64,
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT, mSlice,
|
||||
mFields, mFieldPairs, mOmpParFor,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
|
|
@ -584,36 +585,36 @@ type
|
|||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr,
|
||||
mCopyStr, mCopyStrLast}
|
||||
# magics that require special semantic checking and
|
||||
# thus cannot be overloaded (also documented in the spec!):
|
||||
SpecialSemMagics* = {
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
|
||||
type
|
||||
|
|
@ -634,21 +635,21 @@ type
|
|||
floatVal*: BiggestFloat
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
strVal*: string
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
sym*: PSym
|
||||
of nkIdent:
|
||||
of nkIdent:
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
comment*: string
|
||||
|
||||
|
||||
TSymSeq* = seq[PSym]
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
data*: TSymSeq
|
||||
|
||||
|
||||
# -------------- backend information -------------------------------
|
||||
TLocKind* = enum
|
||||
TLocKind* = enum
|
||||
locNone, # no location
|
||||
locTemp, # temporary location
|
||||
locLocalVar, # location is a local variable
|
||||
|
|
@ -660,7 +661,7 @@ type
|
|||
locData, # location is a constant
|
||||
locCall, # location is a call expression
|
||||
locOther # location is something other
|
||||
TLocFlag* = enum
|
||||
TLocFlag* = enum
|
||||
lfIndirect, # backend introduced a pointer
|
||||
lfParamCopy, # backend introduced a parameter copy (LLVM)
|
||||
lfNoDeepCopy, # no need for a deep copy
|
||||
|
|
@ -670,13 +671,13 @@ type
|
|||
lfHeader, # include header file for symbol
|
||||
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||
lfSingleUse # no location yet and will only be used once
|
||||
TStorageLoc* = enum
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStack, # location is on hardware stack
|
||||
OnHeap # location is on heap or global
|
||||
# (reference counting needed)
|
||||
TLocFlags* = set[TLocFlag]
|
||||
TLoc* = object
|
||||
TLoc* = object
|
||||
k*: TLocKind # kind of location
|
||||
s*: TStorageLoc
|
||||
flags*: TLocFlags # location's flags
|
||||
|
|
@ -688,7 +689,7 @@ type
|
|||
|
||||
# ---------------- end of backend information ------------------------------
|
||||
|
||||
TLibKind* = enum
|
||||
TLibKind* = enum
|
||||
libHeader, libDynamic
|
||||
TLib* = object of lists.TListEntry # also misused for headers!
|
||||
kind*: TLibKind
|
||||
|
|
@ -696,17 +697,17 @@ type
|
|||
isOverriden*: bool
|
||||
name*: PRope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
|
||||
TInstantiation* = object
|
||||
sym*: PSym
|
||||
concreteTypes*: seq[PType]
|
||||
usedBy*: seq[int32] # list of modules using the generic
|
||||
# needed in caas mode for purging the cache
|
||||
# XXX: it's possible to switch to a
|
||||
# XXX: it's possible to switch to a
|
||||
# simple ref count here
|
||||
|
||||
|
||||
PInstantiation* = ref TInstantiation
|
||||
|
||||
|
||||
TScope* = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
|
|
@ -773,7 +774,7 @@ type
|
|||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# it won't cause problems
|
||||
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TLockLevel* = distinct int16
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
|
|
@ -806,7 +807,7 @@ type
|
|||
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||
loc*: TLoc
|
||||
|
||||
TPair*{.final.} = object
|
||||
TPair*{.final.} = object
|
||||
key*, val*: RootRef
|
||||
|
||||
TPairSeq* = seq[TPair]
|
||||
|
|
@ -814,7 +815,7 @@ type
|
|||
counter*: int
|
||||
data*: TPairSeq
|
||||
|
||||
TIdPair*{.final.} = object
|
||||
TIdPair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: RootRef
|
||||
|
||||
|
|
@ -823,7 +824,7 @@ type
|
|||
counter*: int
|
||||
data*: TIdPairSeq
|
||||
|
||||
TIdNodePair*{.final.} = object
|
||||
TIdNodePair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: PNode
|
||||
|
||||
|
|
@ -832,7 +833,7 @@ type
|
|||
counter*: int
|
||||
data*: TIdNodePairSeq
|
||||
|
||||
TNodePair*{.final.} = object
|
||||
TNodePair*{.final.} = object
|
||||
h*: THash # because it is expensive to compute!
|
||||
key*: PNode
|
||||
val*: int
|
||||
|
|
@ -844,7 +845,7 @@ type
|
|||
data*: TNodePairSeq
|
||||
|
||||
TObjectSeq* = seq[RootRef]
|
||||
TObjectSet*{.final.} = object
|
||||
TObjectSet*{.final.} = object
|
||||
counter*: int
|
||||
data*: TObjectSeq
|
||||
|
||||
|
|
@ -855,27 +856,27 @@ type
|
|||
# same name as an imported module. This is necessary because of
|
||||
# the poor naming choices in the standard library.
|
||||
|
||||
const
|
||||
const
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
|
||||
tyVarargs}
|
||||
|
||||
|
||||
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
|
||||
# var x = expr
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
|
||||
tyPointer,
|
||||
tyPointer,
|
||||
tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64}
|
||||
IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
|
||||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
tyTuple, tySequence}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||
tyProc, tyString, tyError}
|
||||
|
|
@ -926,17 +927,17 @@ proc discardSons*(father: PNode)
|
|||
proc len*(n: PNode): int {.inline.} =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc safeLen*(n: PNode): int {.inline.} =
|
||||
## works even for leaves.
|
||||
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc add*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
|
|
@ -946,13 +947,10 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
|||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
#result.info = UnknownLineInfo() inlined:
|
||||
|
|
@ -966,24 +964,24 @@ proc newNode*(kind: TNodeKind): PNode =
|
|||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newIntNode(kind, intVal)
|
||||
result.typ = typ
|
||||
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.name = name
|
||||
|
|
@ -994,7 +992,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
|||
result.owner = owner
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
|
@ -1036,54 +1034,54 @@ proc appendToModule*(m: PSym, n: PNode) =
|
|||
else:
|
||||
assert m.ast.kind == nkStmtList
|
||||
m.ast.sons.add(n)
|
||||
|
||||
|
||||
const # for all kind of hash tables:
|
||||
GrowthFactor* = 2 # must be power of 2, > 0
|
||||
StartSize* = 8 # must be power of 2, > 0
|
||||
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
newSeq(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyTable*(dest: var TTable, src: TTable) =
|
||||
|
||||
proc copyTable*(dest: var TTable, src: TTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc discardSons*(father: PNode) =
|
||||
|
||||
proc discardSons*(father: PNode) =
|
||||
father.sons = nil
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
result = newNode(nkIdent)
|
||||
result.ident = ident
|
||||
result.info = info
|
||||
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
result.info = sym.info
|
||||
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
|
|
@ -1128,12 +1126,12 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
|||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
result.typ = typ
|
||||
|
||||
proc addSon*(father, son: PNode) =
|
||||
proc addSon*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
|
@ -1159,7 +1157,7 @@ proc `$`*(x: TLockLevel): string =
|
|||
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
|
||||
else: result = $int16(x)
|
||||
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.owner = owner
|
||||
|
|
@ -1171,7 +1169,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
|
|||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(a.k): a.k = b.k
|
||||
if a.s == low(a.s): a.s = b.s
|
||||
|
|
@ -1180,37 +1178,37 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
|||
if a.r == nil: a.r = b.r
|
||||
#if a.a == 0: a.a = b.a
|
||||
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int =
|
||||
proc sonsLen*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon*(n: PType): PType =
|
||||
proc lastSon*(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
dest.flags = src.flags
|
||||
dest.callConv = src.callConv
|
||||
|
|
@ -1230,23 +1228,23 @@ proc assignType*(dest, src: PType) =
|
|||
dest.sym = src.sym
|
||||
newSons(dest, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
|
||||
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
result = newType(t.kind, owner)
|
||||
assignType(result, t)
|
||||
if keepId:
|
||||
if keepId:
|
||||
result.id = t.id
|
||||
else:
|
||||
else:
|
||||
when debugIds: registerId(result)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
if keepId:
|
||||
result.id = s.id
|
||||
else:
|
||||
else:
|
||||
result.id = getID()
|
||||
when debugIds: registerId(result)
|
||||
result.flags = s.flags
|
||||
|
|
@ -1273,19 +1271,19 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
|||
result.annex = s.annex
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initTable(x: var TTable) =
|
||||
proc initTable(x: var TTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
|
|
@ -1295,15 +1293,15 @@ proc resetIdTable*(x: var TIdTable) =
|
|||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
|
|
@ -1320,18 +1318,18 @@ proc isGCedMem*(t: PType): bool {.inline.} =
|
|||
t.kind == tyProc and t.callConv == ccClosure
|
||||
|
||||
proc propagateToOwner*(owner, elem: PType) =
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
|
||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||
if tfNotNil in elem.flags:
|
||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||
owner.flags.incl tfNotNil
|
||||
elif owner.kind notin HaveTheirOwnEmpty:
|
||||
owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if tfNeedsInit in elem.flags:
|
||||
if owner.kind in HaveTheirOwnEmpty: discard
|
||||
else: owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
|
|
@ -1348,15 +1346,15 @@ proc addSonNilAllowed*(father, son: PNode) =
|
|||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
# does not copy its sons!
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
|
|
@ -1373,7 +1371,7 @@ proc copyNode*(src: PNode): PNode =
|
|||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
# does not copy its sons, but provides space for them:
|
||||
if src == nil: return nil
|
||||
result = newNode(src.kind)
|
||||
|
|
@ -1391,9 +1389,9 @@ proc shallowCopy*(src: PNode): PNode =
|
|||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: newSeq(result.sons, sonsLen(src))
|
||||
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
# copy a whole syntax tree; performs deep copying
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
|
|
@ -1408,20 +1406,20 @@ proc copyTree*(src: PNode): PNode =
|
|||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else:
|
||||
else:
|
||||
newSeq(result.sons, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1):
|
||||
for i in countup(0, sonsLen(src) - 1):
|
||||
result.sons[i] = copyTree(src.sons[i])
|
||||
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return true
|
||||
elif hasNilSon(n.sons[i]):
|
||||
return true
|
||||
|
|
@ -1435,47 +1433,47 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
|||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.kind in kinds or containsNode(n.sons[i], kinds): return true
|
||||
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind == kind
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
case a.kind
|
||||
of nkIntLit..nkUInt64Lit: result = a.intVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getInt")
|
||||
result = 0
|
||||
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getFloat")
|
||||
result = 0.0
|
||||
|
||||
proc getStr*(a: PNode): string =
|
||||
proc getStr*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getStr")
|
||||
result = ""
|
||||
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
|
||||
|
|
@ -1483,7 +1481,7 @@ proc getStrOrChar*(a: PNode): string =
|
|||
internalError(a.info, "getStrOrChar")
|
||||
result = ""
|
||||
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
case s.kind
|
||||
of skProcKinds:
|
||||
result = sfFromGeneric in s.flags or
|
||||
|
|
|
|||
|
|
@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
|
|||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc spaces(x: int): PRope =
|
||||
proc rspaces(x: int): PRope =
|
||||
# returns x spaces
|
||||
result = toRope(repeatChar(x))
|
||||
result = toRope(spaces(x))
|
||||
|
||||
proc toYamlChar(c: char): string =
|
||||
case c
|
||||
|
|
@ -253,7 +253,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet,
|
|||
indent, maxRecDepth: int): PRope
|
||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = toRope("[")
|
||||
var mycount = 0
|
||||
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",
|
||||
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
||||
inc(mycount)
|
||||
if mycount > 0: appf(result, "$N$1", [spaces(indent)])
|
||||
if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
|
||||
app(result, "]")
|
||||
assert(mycount == n.counter)
|
||||
|
||||
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||
# array of (name, value) pairs
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = toRope("{")
|
||||
var i = 0
|
||||
while i <= high(c):
|
||||
if i > 0: app(result, ",")
|
||||
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
||||
inc(i, 2)
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
appf(result, "$N$1}", [rspaces(indent)])
|
||||
|
||||
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
|
|
@ -310,9 +310,9 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
|||
result = toRope("[")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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)])
|
||||
appf(result, "$N$1]", [spaces(indent + 2)])
|
||||
appf(result, "$N$1]", [rspaces(indent + 2)])
|
||||
else:
|
||||
result = toRope("null")
|
||||
result = ropeConstr(indent, [toRope("kind"),
|
||||
|
|
@ -331,7 +331,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
|||
if n == nil:
|
||||
result = toRope("null")
|
||||
else:
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
||||
if maxRecDepth != 0:
|
||||
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])
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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)])
|
||||
appf(result, "$N$1]", [istr])
|
||||
appf(result, ",$N$1\"typ\": $2",
|
||||
[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 =
|
||||
var marker = initIntSet()
|
||||
|
|
@ -408,7 +408,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
|||
if n == nil:
|
||||
result = toRope("null")
|
||||
else:
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = ropef("{$N$1\"kind\": $2",
|
||||
[istr, makeYamlString($n.kind)])
|
||||
if maxRecDepth != 0:
|
||||
|
|
@ -440,11 +440,11 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
|||
appf(result, ",$N$1\"sons\": [", [istr])
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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)])
|
||||
appf(result, "$N$1]", [istr])
|
||||
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) =
|
||||
if n == nil:
|
||||
|
|
@ -681,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
|||
else: result = nextIdentIter(ti, tab)
|
||||
|
||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
var h, start: THash
|
||||
h = ti.h and high(tab.data)
|
||||
start = h
|
||||
var h = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
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):
|
||||
initLocExpr(p, n, 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:
|
||||
initLocExprSingleUse(p, n.sons[0], a)
|
||||
# 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.
|
||||
let callee = call.sons[0]
|
||||
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 != {}:
|
||||
result = addrLoc(a)
|
||||
else:
|
||||
|
|
@ -192,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
var op: TLoc
|
||||
initLocExpr(p, ri.sons[0], op)
|
||||
var pl: PRope
|
||||
|
||||
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
|
|
@ -204,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
else:
|
||||
app(pl, genArgNoParam(p, ri.sons[i]))
|
||||
if i < length - 1: app(pl, ~", ")
|
||||
|
||||
|
||||
template genCallPattern {.dirty.} =
|
||||
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)
|
||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||
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:
|
||||
result.app(~", ")
|
||||
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
|
||||
of tyChar, tyNil:
|
||||
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:
|
||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||
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)
|
||||
if id == gBackendId:
|
||||
# string literal not found in the cache:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||
[getStrLit(p.module, n.strVal)])
|
||||
else:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
|
||||
|
|
@ -158,7 +153,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
|||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in n.sym.flags: result = OnHeap
|
||||
else: result = OnStack
|
||||
of skConst:
|
||||
of skConst:
|
||||
if sfGlobal in n.sym.flags: result = OnHeap
|
||||
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:
|
||||
let t = t.sons[i]
|
||||
let field = ropef("Field$1", i.toRope)
|
||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||
optAsgnLoc(src, t, field), newflags)
|
||||
|
||||
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
|
||||
of nkSym:
|
||||
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)
|
||||
of nkRecList:
|
||||
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
|
||||
else: discard
|
||||
|
||||
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
# Consider:
|
||||
# Consider:
|
||||
# type TMyFastString {.shallow.} = string
|
||||
# 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
|
||||
# here for this flag, where it is reasonably safe to do so
|
||||
# (for objects, etc.):
|
||||
if needToCopy notin flags or
|
||||
if needToCopy notin flags or
|
||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||
if dest.s == OnStack or not usesNativeGC():
|
||||
useStringh(p.module)
|
||||
|
|
@ -510,7 +505,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
|||
var storage: PRope
|
||||
var size = getSize(t)
|
||||
if size < platform.intSize:
|
||||
storage = toRope("NI")
|
||||
storage = toRope("NI")
|
||||
else:
|
||||
storage = getTypeDesc(p.module, t)
|
||||
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))", # MulF64
|
||||
"(($4)($1) / ($4)($2))", # DivF64
|
||||
|
||||
|
||||
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
|
||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||
"($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[2], b)
|
||||
if a.t.callConv == ccClosure:
|
||||
putIntoDest(p, d, e.typ,
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
|
||||
rdLoc(a), rdLoc(b)]))
|
||||
else:
|
||||
|
|
@ -721,7 +716,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
|
|||
if d.k == locNone: d.s = a.s
|
||||
if d.heapRoot == nil:
|
||||
d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
|
||||
|
||||
|
||||
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
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)
|
||||
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||
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) =
|
||||
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})
|
||||
gcUsage(e)
|
||||
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[1], a)
|
||||
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
|
|
@ -1120,14 +1115,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
|||
else:
|
||||
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
||||
genAssignment(p, dest, call, {needToKeepAlive})
|
||||
|
||||
|
||||
proc genNewSeq(p: BProc, e: PNode) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
genNewSeqAux(p, a, b.rdLoc)
|
||||
gcUsage(e)
|
||||
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
var tmp: TLoc
|
||||
var t = e.typ.skipTypes(abstractInst)
|
||||
|
|
@ -1168,7 +1163,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
|||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {})
|
||||
|
||||
|
||||
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
||||
var arr: TLoc
|
||||
if d.k == locNone:
|
||||
|
|
@ -1192,7 +1187,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
|||
getTemp(p, t.typ, d)
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
var L = int(lengthOrd(t.sons[1].typ))
|
||||
|
||||
|
||||
genNewSeqAux(p, d, intLiteral(L))
|
||||
initLocExpr(p, t.sons[1], a)
|
||||
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)
|
||||
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
|
||||
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
||||
|
||||
|
||||
proc genNewFinalize(p: BProc, e: PNode) =
|
||||
var
|
||||
a, b, f: TLoc
|
||||
|
|
@ -1258,7 +1253,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
|||
app(r, ~".Sup")
|
||||
t = skipTypes(t.sons[0], typedescInst)
|
||||
if isObjLackingTypeField(t):
|
||||
globalError(x.info, errGenerated,
|
||||
globalError(x.info, errGenerated,
|
||||
"no 'of' operator available for pure objects")
|
||||
if nilCheck != nil:
|
||||
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)
|
||||
case t.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
putIntoDest(p, d, e.typ,
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
||||
of tyFloat..tyFloat128:
|
||||
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:
|
||||
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
||||
of tyString, tySequence:
|
||||
putIntoDest(p, b, e.typ,
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
||||
of tyArray, tyArrayConstr:
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
||||
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),
|
||||
genTypeInfo(p.module, elemType(t))]))
|
||||
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
|
||||
# so, we skip the unnecessary range check: This is a semantical extension
|
||||
# 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]
|
||||
else:
|
||||
e.sons[2]
|
||||
|
|
@ -1518,7 +1513,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
|||
initLocExpr(p, e.sons[2], b)
|
||||
if d.k == locNone: getTemp(p, a.t, d)
|
||||
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", [
|
||||
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
|
||||
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) =
|
||||
const floatTypes = {tyFloat..tyFloat128}
|
||||
let
|
||||
let
|
||||
destt = skipTypes(e.typ, abstractRange)
|
||||
srct = skipTypes(e.sons[1].typ, abstractRange)
|
||||
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 mGetTypeInfo: genGetTypeInfo(p, e, d)
|
||||
of mSwap: genSwap(p, e, d)
|
||||
of mUnaryLt:
|
||||
of mUnaryLt:
|
||||
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||
of mPred:
|
||||
|
|
@ -1830,10 +1825,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
|||
proc isConstClosure(n: PNode): bool {.inline.} =
|
||||
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
|
||||
n.sons[1].kind == nkNilLit
|
||||
|
||||
|
||||
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||
assert n.kind == nkClosure
|
||||
|
||||
|
||||
if isConstClosure(n):
|
||||
inc(p.labels)
|
||||
var tmp = con("LOC", toRope(p.labels))
|
||||
|
|
@ -1920,7 +1915,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
|||
if isRef:
|
||||
# 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
|
||||
# (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
|
||||
# this by ensuring the destination is also a pointer:
|
||||
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
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
var tmp = con("TMP", toRope(id))
|
||||
|
||||
|
||||
if id == gBackendId:
|
||||
# expression not found in the cache:
|
||||
inc(gBackendId)
|
||||
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
||||
|
||||
|
||||
if d.k == locNone:
|
||||
fillLoc(d, locData, t, tmp, OnHeap)
|
||||
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
|
||||
if sfThread in sym.flags:
|
||||
accessThreadLocalVar(p, sym)
|
||||
if emulatedThreadVars():
|
||||
if emulatedThreadVars():
|
||||
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
|
||||
else:
|
||||
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
|
||||
#debug p.prc.typ.n
|
||||
#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)
|
||||
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||
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
|
||||
# separate compilation:
|
||||
genTypeSection(p.module, n)
|
||||
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
discard
|
||||
of nkPragma: genPragma(p, n)
|
||||
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
|
||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
(prc.kind == skMethod):
|
||||
# we have not only the header:
|
||||
(prc.kind == skMethod):
|
||||
# we have not only the header:
|
||||
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
|
||||
genProc(p.module, prc)
|
||||
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 =
|
||||
var data = ropef("{{$1, $1}", n.len.toRope)
|
||||
if n.len > 0:
|
||||
if n.len > 0:
|
||||
# array part needs extra curlies:
|
||||
data.app(", {")
|
||||
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("}")
|
||||
data.app("}")
|
||||
|
||||
|
||||
inc(gBackendId)
|
||||
result = con("CNSTSEQ", gBackendId.toRope)
|
||||
|
||||
|
||||
appcg(p.module, cfsData,
|
||||
"NIM_CONST struct {$n" &
|
||||
"NIM_CONST struct {$n" &
|
||||
" #TGenericSeq Sup;$n" &
|
||||
" $1 data[$2];$n" &
|
||||
" $1 data[$2];$n" &
|
||||
"} $3 = $4;$n", [
|
||||
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.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
||||
import
|
||||
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
||||
platform, trees
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in 0 .. < n.len:
|
||||
of nkStmtList:
|
||||
for i in 0 .. < n.len:
|
||||
result = getPragmaStmt(n[i], w)
|
||||
if result != nil: break
|
||||
of nkPragma:
|
||||
for i in 0 .. < n.len:
|
||||
for i in 0 .. < n.len:
|
||||
if whichPragma(n[i]) == w: return n[i]
|
||||
else: discard
|
||||
|
||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||
result = getPragmaStmt(n, w) != nil
|
||||
|
||||
proc hashString*(s: string): BiggestInt =
|
||||
proc hashString*(s: string): BiggestInt =
|
||||
# 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
|
||||
# as the target CPU
|
||||
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 +% `shl`(b, 10)
|
||||
b = b xor `shr`(b, 6)
|
||||
|
|
@ -41,9 +41,9 @@ proc hashString*(s: string): BiggestInt =
|
|||
b = b xor `shr`(b, 11)
|
||||
b = b +% `shl`(b, 15)
|
||||
result = b
|
||||
else:
|
||||
else:
|
||||
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 +% `shl`(a, 10'i32)
|
||||
a = a xor `shr`(a, 6'i32)
|
||||
|
|
@ -52,11 +52,11 @@ proc hashString*(s: string): BiggestInt =
|
|||
a = a +% `shl`(a, 15'i32)
|
||||
result = a
|
||||
|
||||
var
|
||||
var
|
||||
gTypeTable: array[TTypeKind, TIdTable]
|
||||
gCanonicalTypes: array[TTypeKind, PType]
|
||||
|
||||
proc initTypeTables() =
|
||||
proc initTypeTables() =
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
|
||||
|
||||
proc resetCaches* =
|
||||
|
|
@ -67,7 +67,7 @@ proc resetCaches* =
|
|||
|
||||
when false:
|
||||
proc echoStats*() =
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||
echo i, " ", gTypeTable[i].counter
|
||||
|
||||
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
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
||||
proc getUniqueType*(key: PType): PType =
|
||||
proc getUniqueType*(key: PType): PType =
|
||||
# this is a hotspot in the compiler!
|
||||
if key == nil: return
|
||||
if key == nil: return
|
||||
var k = key.kind
|
||||
case k
|
||||
of tyBool, tyChar, tyInt..tyUInt64:
|
||||
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
||||
# produced instead of ``NI``.
|
||||
result = key
|
||||
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
||||
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
||||
tyCString, tyNone, tyBigNum:
|
||||
result = gCanonicalTypes[k]
|
||||
if result == nil:
|
||||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||
internalError("GetUniqueType")
|
||||
internalError("getUniqueType")
|
||||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
|
|
@ -127,21 +127,21 @@ proc getUniqueType*(key: PType): PType =
|
|||
if tfFromGeneric notin key.flags:
|
||||
# fast case; lookup per id suffices:
|
||||
result = PType(idTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
else:
|
||||
# ugly slow case: need to compare by structure
|
||||
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)
|
||||
if t != nil and sameType(t, key):
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
result = key
|
||||
of tyEnum:
|
||||
result = PType(idTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
of tyProc:
|
||||
|
|
@ -151,16 +151,16 @@ proc getUniqueType*(key: PType): PType =
|
|||
# ugh, we need the canon here:
|
||||
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
|
||||
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
|
||||
# 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)
|
||||
if t != nil:
|
||||
if sameType(t, key):
|
||||
if t != nil:
|
||||
if sameType(t, key):
|
||||
return tab.data[h].val
|
||||
|
||||
proc makeSingleLineCString*(s: string): string =
|
||||
|
|
@ -193,16 +193,16 @@ proc mangle*(name: string): string =
|
|||
else:
|
||||
add(result, "HEX" & toHex(ord(c), 2))
|
||||
|
||||
proc makeLLVMString*(s: string): PRope =
|
||||
proc makeLLVMString*(s: string): PRope =
|
||||
const MaxLineLength = 64
|
||||
result = nil
|
||||
var res = "c\""
|
||||
for i in countup(0, len(s) - 1):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
for i in countup(0, len(s) - 1):
|
||||
if (i + 1) mod MaxLineLength == 0:
|
||||
app(result, toRope(res))
|
||||
setLen(res, 0)
|
||||
case s[i]
|
||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
||||
add(res, '\\')
|
||||
add(res, toHex(ord(s[i]), 2))
|
||||
else: add(res, s[i])
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
|||
let field = getField(typ.n, i)
|
||||
pack(it, field.typ, res +! field.offset)
|
||||
else:
|
||||
# XXX: todo
|
||||
globalError(x.info, "cannot pack unnamed tuple")
|
||||
|
||||
const maxPackDepth = 20
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
|
||||
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
|
||||
rodread
|
||||
|
||||
type
|
||||
|
|
@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
|||
result.add copyNode(c, templ, actual)
|
||||
else:
|
||||
var res = copyNode(c, templ, actual)
|
||||
for i in countup(0, sonsLen(templ) - 1):
|
||||
for i in countup(0, sonsLen(templ) - 1):
|
||||
evalTemplateAux(templ.sons[i], actual, c, res)
|
||||
result.add res
|
||||
|
||||
|
|
@ -86,9 +86,9 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
|||
ctx.owner = tmpl
|
||||
ctx.genSymOwner = genSymOwner
|
||||
initIdTable(ctx.mapping)
|
||||
|
||||
|
||||
let body = tmpl.getBody
|
||||
if isAtom(body):
|
||||
if isAtom(body):
|
||||
result = newNodeI(nkPar, body.info)
|
||||
evalTemplateAux(body, args, ctx, result)
|
||||
if result.len == 1: result = result.sons[0]
|
||||
|
|
@ -102,5 +102,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
|||
if ctx.instLines: result.info = n.info
|
||||
for i in countup(0, safeLen(body) - 1):
|
||||
evalTemplateAux(body.sons[i], args, ctx, result)
|
||||
|
||||
|
||||
dec(evalTemplateCounter)
|
||||
|
|
|
|||
|
|
@ -572,6 +572,9 @@ proc footprint(filename: string): TCrc32 =
|
|||
getCompileCFileCmd(filename, true)
|
||||
|
||||
proc externalFileChanged(filename: string): bool =
|
||||
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||
return false
|
||||
|
||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||
var currentCrc = int(footprint(filename))
|
||||
var f: File
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ const
|
|||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||
|
||||
proc newLine(p: var TTmplParser) =
|
||||
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
||||
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||
p.emitPar = 0
|
||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||
if p.pendingExprLine:
|
||||
llStreamWrite(p.outp, repeatChar(2))
|
||||
llStreamWrite(p.outp, spaces(2))
|
||||
p.pendingExprLine = false
|
||||
|
||||
proc scanPar(p: var TTmplParser, d: int) =
|
||||
|
|
@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
|
|||
else:
|
||||
p.info.col = int16(j)
|
||||
localError(p.info, errXNotAllowedHere, "end")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, "#end")
|
||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||
wConverter, wMacro, wTemplate, wMethod:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
inc(p.indent, 2)
|
||||
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))
|
||||
of wLet, wVar, wConst, wType:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
if not p.x.contains({':', '='}):
|
||||
# no inline element --> treat as block:
|
||||
inc(p.indent, 2)
|
||||
else:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
p.state = psDirective
|
||||
else:
|
||||
|
|
@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
|
|||
# next line of string literal:
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, "\n")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent + 2))
|
||||
llStreamWrite(p.outp, spaces(p.indent + 2))
|
||||
llStreamWrite(p.outp, "\"")
|
||||
of psDirective:
|
||||
newLine(p)
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, p.emit)
|
||||
llStreamWrite(p.outp, "(\"")
|
||||
inc(p.emitPar)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
|
|||
result = n.ident.s
|
||||
of nkSym:
|
||||
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:
|
||||
# XXX hack ahead:
|
||||
n.kind = nkImportAs
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
|||
moveInto(p, stmt, r)
|
||||
appf(p.body, "}$n" | "end$n")
|
||||
if p.target == targetJS:
|
||||
app(p.body, repeatChar(toClose, '}') & tnl)
|
||||
app(p.body, repeat('}', toClose) & tnl)
|
||||
else:
|
||||
for i in 1..toClose: appf(p.body, "end$n")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ proc llStreamOpen*(data: string): PLLStream =
|
|||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc llStreamOpen*(f: var File): PLLStream =
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
|||
if sfExported in sym.flags:
|
||||
# add to interface:
|
||||
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) =
|
||||
addDeclAt(scope, sym)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ type
|
|||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
|
|
@ -391,6 +392,7 @@ const
|
|||
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]",
|
||||
warnLockLevel: "$1 [LockLevel]",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
|
||||
warnUser: "$1 [User]",
|
||||
hintSuccess: "operation successful [Success]",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||
|
|
@ -411,7 +413,7 @@ const
|
|||
hintUser: "$1 [User]"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape",
|
||||
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
|
|
@ -421,7 +423,7 @@ const
|
|||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "User"]
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||
|
||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
|
|
@ -784,7 +786,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
|||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||
msgWriteln(indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let frmt = case msg
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ define:useStdoutAsStdmsg
|
|||
cs:partial
|
||||
#define:useNodeIds
|
||||
symbol:nimfix
|
||||
#gc:markAndSweep
|
||||
|
|
|
|||
|
|
@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
|||
inc(i)
|
||||
result.add("\n")
|
||||
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 ']'
|
||||
#| extTupleDecl = 'tuple'
|
||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
#| tupleClass = 'tuple'
|
||||
result = newNodeP(nkTupleTy, p)
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkBracketLe:
|
||||
|
|
@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
|||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
if not sameInd(p): break
|
||||
else:
|
||||
result = newNodeP(nkTupleClassTy, p)
|
||||
|
||||
proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@
|
|||
# This module implements the passes functionality. A pass must implement the
|
||||
# `TPass` interface.
|
||||
|
||||
import
|
||||
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||
import
|
||||
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||
nimsets, syntaxes, times, rodread, idgen
|
||||
|
||||
type
|
||||
type
|
||||
TPassContext* = object of RootObj # the pass's context
|
||||
fromCache*: bool # true if created by "openCached"
|
||||
|
||||
|
||||
PPassContext* = ref TPassContext
|
||||
|
||||
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
||||
|
|
@ -33,8 +33,8 @@ type
|
|||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||
TPasses* = openArray[TPass]
|
||||
|
||||
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
||||
# nodes. These are passed to the other close procedures.
|
||||
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
||||
# nodes. These are passed to the other close procedures.
|
||||
# This mechanism used to be used for the instantiation of generics.
|
||||
|
||||
proc makePass*(open: TPassOpen = nil,
|
||||
|
|
@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil,
|
|||
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
||||
|
||||
# the semantic checker needs these:
|
||||
var
|
||||
var
|
||||
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
||||
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
||||
|
||||
# implementation
|
||||
|
||||
proc skipCodegen*(n: PNode): bool {.inline.} =
|
||||
# can be used by codegen passes to determine whether they should do
|
||||
proc skipCodegen*(n: PNode): bool {.inline.} =
|
||||
# can be used by codegen passes to determine whether they should do
|
||||
# something with `n`. Currently, this ignores `n` and uses the global
|
||||
# error count instead.
|
||||
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
|
||||
# needs to be stored. The passes manager frees s.sons[codePos] when
|
||||
# appropriate to free the procedure body's memory. This is important
|
||||
# to keep memory usage down.
|
||||
if (s.kind in {skMethod, skProc}) and
|
||||
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
||||
(s.typ.callConv != ccInline) and
|
||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
||||
(s.typ.callConv != ccInline) and
|
||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
||||
result = false
|
||||
# XXX this doesn't really make sense with excessive CTFE
|
||||
else:
|
||||
result = true
|
||||
|
||||
const
|
||||
|
||||
const
|
||||
maxPasses = 10
|
||||
|
||||
type
|
||||
type
|
||||
TPassContextArray = array[0..maxPasses - 1, PPassContext]
|
||||
|
||||
var
|
||||
var
|
||||
gPasses: array[0..maxPasses - 1, TPass]
|
||||
gPassesLen*: int
|
||||
|
||||
proc clearPasses* =
|
||||
gPassesLen = 0
|
||||
|
||||
proc registerPass*(p: TPass) =
|
||||
proc registerPass*(p: TPass) =
|
||||
gPasses[gPassesLen] = p
|
||||
inc(gPassesLen)
|
||||
|
||||
|
|
@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
|
|||
passdata = carryPass(pass, module, passdata)
|
||||
|
||||
proc openPasses(a: var TPassContextArray, module: PSym) =
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].open):
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].open):
|
||||
a[i] = gPasses[i].open(module)
|
||||
else: a[i] = nil
|
||||
|
||||
|
||||
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].openCached):
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].openCached):
|
||||
a[i] = gPasses[i].openCached(module, rd)
|
||||
if a[i] != nil:
|
||||
if a[i] != nil:
|
||||
a[i].fromCache = true
|
||||
else:
|
||||
a[i] = nil
|
||||
|
||||
proc closePasses(a: var TPassContextArray) =
|
||||
|
||||
proc closePasses(a: var TPassContextArray) =
|
||||
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)
|
||||
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
|
||||
var m = n
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].process):
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].process):
|
||||
m = gPasses[i].process(a[i], m)
|
||||
if isNil(m): return false
|
||||
result = true
|
||||
|
||||
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
||||
|
||||
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
||||
# this implements the code transformation pipeline
|
||||
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)
|
||||
|
||||
proc closePassesCached(a: var TPassContextArray) =
|
||||
|
||||
proc closePassesCached(a: var TPassContextArray) =
|
||||
var m: PNode = nil
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
||||
for i in countup(0, gPassesLen - 1):
|
||||
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
||||
m = gPasses[i].close(a[i], m)
|
||||
a[i] = nil # free the memory here
|
||||
|
||||
|
||||
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||
a: var TPassContextArray) =
|
||||
for module in items(implicits):
|
||||
|
|
@ -159,45 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
|||
str.info = gCmdLineInfo
|
||||
importStmt.addSon str
|
||||
if not processTopLevelStmt(importStmt, a): break
|
||||
|
||||
|
||||
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||
var
|
||||
var
|
||||
p: TParsers
|
||||
a: TPassContextArray
|
||||
s: PLLStream
|
||||
fileIdx = module.fileIdx
|
||||
if rd == nil:
|
||||
if rd == nil:
|
||||
openPasses(a, module)
|
||||
if stream == nil:
|
||||
if stream == nil:
|
||||
let filename = fileIdx.toFullPathConsiderDirty
|
||||
if module.name.s == "-":
|
||||
module.name.s = "stdinfile"
|
||||
s = llStreamOpenStdIn()
|
||||
s = llStreamOpen(stdin)
|
||||
else:
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
if s == nil:
|
||||
rawMessage(errCannotOpenFile, filename)
|
||||
return
|
||||
else:
|
||||
s = stream
|
||||
while true:
|
||||
while true:
|
||||
openParsers(p, fileIdx, s)
|
||||
|
||||
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
|
||||
# in ROD files. I think we should enable this feature only
|
||||
# for the interactive mode.
|
||||
processImplicits implicitImports, nkImportStmt, a
|
||||
processImplicits implicitIncludes, nkIncludeStmt, a
|
||||
|
||||
while true:
|
||||
while true:
|
||||
var n = parseTopLevelStmt(p)
|
||||
if n.kind == nkEmpty: break
|
||||
if n.kind == nkEmpty: break
|
||||
if not processTopLevelStmt(n, a): break
|
||||
|
||||
closeParsers(p)
|
||||
if s.kind != llsStdIn: break
|
||||
if s.kind != llsStdIn: break
|
||||
closePasses(a)
|
||||
# id synchronization point for more consistent code generation:
|
||||
idSynchronizationPoint(1000)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
|||
|
||||
proc addPendingNL(g: var TSrcGen) =
|
||||
if g.pendingNL >= 0:
|
||||
addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
|
||||
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
|
||||
g.lineLen = g.pendingNL
|
||||
g.pendingNL = - 1
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
|||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||
put(g, tkComment, com)
|
||||
optNL(g, ind)
|
||||
com = '#' & repeatChar(comIndent)
|
||||
com = '#' & spaces(comIndent)
|
||||
while s[i] > ' ':
|
||||
add(com, s[i])
|
||||
inc(i)
|
||||
|
|
@ -280,7 +280,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
|
|||
(g.lineLen < LineCommentColumn):
|
||||
var ml = maxLineLength(n.comment)
|
||||
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);
|
||||
|
||||
proc gcoms(g: var TSrcGen) =
|
||||
|
|
@ -395,6 +395,7 @@ proc lsub(n: PNode): int =
|
|||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
result = lsons(n) + len("()") + sonsLen(n) - 1
|
||||
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
||||
of nkTupleClassTy: result = len("tuple")
|
||||
of nkDotExpr: result = lsons(n) + 1
|
||||
of nkBind: result = lsons(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])
|
||||
of nkTupleTy:
|
||||
put(g, tkTuple, "tuple")
|
||||
if sonsLen(n) > 0:
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkTupleClassTy:
|
||||
put(g, tkTuple, "tuple")
|
||||
of nkMetaNode_Obsolete:
|
||||
put(g, tkParLe, "(META|")
|
||||
gsub(g, n.sons[0])
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
|||
echo "passing to safeSemExpr: ", renderTree(n)
|
||||
discard safeSemExpr(c, n)
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||
typeToString(actual) & ") " &
|
||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||
|
|
@ -113,7 +113,7 @@ proc commonType*(x, y: PType): PType =
|
|||
else:
|
||||
result = newType(tyTypeDesc, 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:
|
||||
# check for seq[empty] vs. seq[int]
|
||||
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
||||
|
|
@ -163,7 +163,7 @@ proc commonType*(x, y: PType): PType =
|
|||
result = newType(k, r.owner)
|
||||
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)
|
||||
|
||||
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,
|
||||
allowed: TSymFlags): PSym
|
||||
# identifier with visability
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym
|
||||
proc semStmtScope(c: PContext, n: PNode): PNode
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
|||
let t = typeAllowed(typ, kind)
|
||||
if t != nil:
|
||||
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) & "'")
|
||||
|
||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||
|
|
@ -226,7 +226,7 @@ when false:
|
|||
result = newSymNode(getSysSym"void")
|
||||
else:
|
||||
result.typ = makeTypeDesc(c, result.typ)
|
||||
|
||||
|
||||
result.handleIsOperator = proc (n: PNode): PNode =
|
||||
result = isOpImpl(c, n)
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
|
|||
if result == nil:
|
||||
result = arg
|
||||
# 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 = eOrig.typ
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
|||
else:
|
||||
case s.typ.sons[0].kind
|
||||
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)
|
||||
# semExprWithType(c, result)
|
||||
result = semExpr(c, result, flags)
|
||||
|
|
@ -355,18 +355,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
|||
result = semAfterMacroCall(c, result, sym, flags)
|
||||
popInfoContext()
|
||||
|
||||
proc forceBool(c: PContext, n: PNode): PNode =
|
||||
proc forceBool(c: PContext, n: PNode): PNode =
|
||||
result = fitNode(c, getSysType(tyBool), 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)
|
||||
result = fitNode(c, getSysType(tyBool), nn)
|
||||
if result == nil:
|
||||
localError(n.info, errConstExprExpected)
|
||||
return nn
|
||||
result = getConstExpr(c.module, result)
|
||||
if result == nil:
|
||||
if result == nil:
|
||||
localError(n.info, errConstExprExpected)
|
||||
result = nn
|
||||
|
||||
|
|
@ -403,9 +403,9 @@ proc myOpen(module: PSym): PPassContext =
|
|||
pushOwner(c.module)
|
||||
c.importTable = openScope(c)
|
||||
c.importTable.addSym(module) # a module knows itself
|
||||
if sfSystemModule in module.flags:
|
||||
if sfSystemModule in module.flags:
|
||||
magicsys.systemModule = module # set global variable!
|
||||
else:
|
||||
else:
|
||||
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
||||
importAllSymbols(c, magicsys.systemModule)
|
||||
c.topLevelScope = openScope(c)
|
||||
|
|
@ -415,13 +415,13 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
|||
result = myOpen(module)
|
||||
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)
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
addCodeForGenerics(c, a)
|
||||
if sonsLen(a) > 0:
|
||||
if sonsLen(a) > 0:
|
||||
# a generic has been added to `a`:
|
||||
if result.kind != nkEmpty: addSon(a, result)
|
||||
result = a
|
||||
|
|
@ -429,17 +429,17 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
|||
if gCmd == cmdInteractive and not isEmptyType(result.typ):
|
||||
result = buildEchoStmt(c, 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
|
||||
# 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.
|
||||
c.currentScope = c.topLevelScope
|
||||
while getCurrOwner().kind != skModule: popOwner()
|
||||
while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
|
||||
|
||||
proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
# no need for an expensive 'try' if we stop after the first error anyway:
|
||||
if msgs.gErrorMax <= 1:
|
||||
result = semStmtAndGenerateGenerics(c, n)
|
||||
|
|
@ -455,8 +455,8 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
|||
if getCurrentException() of ESuggestDone: result = nil
|
||||
else: result = ast.emptyNode
|
||||
#if gCmd == cmdIdeTools: findSuggest(c, n)
|
||||
|
||||
proc myClose(context: PPassContext, n: PNode): PNode =
|
||||
|
||||
proc myClose(context: PPassContext, n: PNode): PNode =
|
||||
var c = PContext(context)
|
||||
closeScope(c) # close module's scope
|
||||
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements semantic checking for calls.
|
||||
## This module implements semantic checking for calls.
|
||||
# included from sem.nim
|
||||
|
||||
proc sameMethodDispatcher(a, b: PSym): bool =
|
||||
result = false
|
||||
if a.kind == skMethod and b.kind == skMethod:
|
||||
if a.kind == skMethod and b.kind == skMethod:
|
||||
var aa = lastSon(a.ast)
|
||||
var bb = lastSon(b.ast)
|
||||
if aa.kind == nkSym and bb.kind == nkSym:
|
||||
if aa.sym == bb.sym:
|
||||
if aa.sym == bb.sym:
|
||||
result = true
|
||||
else:
|
||||
discard
|
||||
|
|
@ -31,7 +31,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
|||
# to avoid subtle problems, the call remains ambiguous and needs to
|
||||
# be disambiguated by the programmer; this way the right generic is
|
||||
# instantiated.
|
||||
|
||||
|
||||
proc determineType(c: PContext, s: PSym)
|
||||
|
||||
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
|
|
@ -41,73 +41,80 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
best, alt: var TCandidate,
|
||||
errors: var CandidateErrors) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
# thanks to the lazy semchecking for operands, we need to iterate over the
|
||||
# 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
|
||||
|
||||
if sym == nil: return
|
||||
initCandidate(c, best, sym, initialBinding, symScope)
|
||||
initCandidate(c, alt, sym, initialBinding, symScope)
|
||||
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
||||
initCandidate(c, alt, syms[0][0], initialBinding, symScope)
|
||||
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:
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: discard
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# 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
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
for i in 0 .. <syms.len:
|
||||
let sym = syms[i][0]
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
||||
z.calleeSym = sym
|
||||
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: discard
|
||||
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
||||
# 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) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if c.inCompilesContext > 0:
|
||||
if c.inCompilesContext > 0:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.isNil or errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
return
|
||||
|
||||
# to avoid confusing errors like:
|
||||
# to avoid confusing errors like:
|
||||
# got (SslPtr, SocketHandle)
|
||||
# but expected one of:
|
||||
# but expected one of:
|
||||
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
||||
# we do a pre-analysis. If all types produce the same string, we will add
|
||||
# module information.
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
|
||||
|
||||
var prefer = preferName
|
||||
for err in errors:
|
||||
var errProto = ""
|
||||
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]
|
||||
if p.kind == nkSym:
|
||||
add(errProto, typeToString(p.sym.typ, preferName))
|
||||
|
|
@ -159,9 +166,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
|
||||
n.sons.insert(hiddenArg, 1)
|
||||
orig.sons.insert(hiddenArg, 1)
|
||||
|
||||
|
||||
pickBest(f)
|
||||
|
||||
|
||||
if result.state != csMatch:
|
||||
n.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
|
||||
n.sons[0..1] = [nil, n[1], calleeName]
|
||||
orig.sons[0..1] = [nil, orig[1], calleeName]
|
||||
|
||||
|
||||
template tryOp(x) =
|
||||
let op = newIdentNode(getIdent(x), n.info)
|
||||
n.sons[0] = op
|
||||
|
|
@ -188,7 +195,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
|
||||
if nfExplicitCall in n.flags:
|
||||
tryOp ".()"
|
||||
|
||||
|
||||
if result.state in {csEmpty, csNoMatch}:
|
||||
tryOp "."
|
||||
|
||||
|
|
@ -199,7 +206,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||
pickBest(callOp)
|
||||
|
||||
|
||||
if overloadsState == csEmpty and result.state == csEmpty:
|
||||
localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
|
||||
return
|
||||
|
|
@ -224,7 +231,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
internalAssert result.state == csMatch
|
||||
#writeMatches(result)
|
||||
#writeMatches(alt)
|
||||
if c.inCompilesContext > 0:
|
||||
if c.inCompilesContext > 0:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
globalError(n.info, errGenerated, "ambiguous call")
|
||||
elif gErrorCounter == 0:
|
||||
|
|
@ -254,7 +261,7 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
|||
for i in 1 .. <n.len:
|
||||
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
|
||||
initCandidate(c, m, f)
|
||||
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:
|
||||
n.sons[1] = n.sons[1].sons[0]
|
||||
notFoundError(c, n, errors)
|
||||
else:
|
||||
else:
|
||||
notFoundError(c, n, errors)
|
||||
# else: result = errorNode(c, n)
|
||||
|
||||
|
|
@ -341,7 +348,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
|||
styleCheckUse(n.info, s)
|
||||
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
|
||||
for i in 1..sonsLen(n)-1:
|
||||
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.
|
||||
# It's good enough for now.
|
||||
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
|
||||
if candidate.kind in {skProc, skMethod, skConverter,
|
||||
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:
|
||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||
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]
|
||||
else: illFormedAst(n)
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||
of nkObjectTy, nkTupleTy:
|
||||
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||
discard
|
||||
of nkFormalParams:
|
||||
checkMinSonsLen(n, 1)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@
|
|||
# included from sem.nim
|
||||
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiation) =
|
||||
if n.kind != nkGenericParams:
|
||||
entry: var TInstantiation) =
|
||||
if n.kind != nkGenericParams:
|
||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
newSeq(entry.concreteTypes, n.len)
|
||||
for i, a in n.pairs:
|
||||
if a.kind != nkSym:
|
||||
if a.kind != nkSym:
|
||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
var q = a.sym
|
||||
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))
|
||||
if t == nil:
|
||||
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
|
||||
t = q.typ
|
||||
else:
|
||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericParam:
|
||||
elif t.kind == tyGenericParam:
|
||||
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericInvocation:
|
||||
|
|
@ -58,17 +58,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
|
|||
if sameInstantiation(entry, inst[]):
|
||||
return inst.sym
|
||||
|
||||
proc removeDefaultParamValues(n: PNode) =
|
||||
proc removeDefaultParamValues(n: PNode) =
|
||||
# we remove default params, because they cannot be instantiated properly
|
||||
# and they are not needed anyway for instantiation (each param is already
|
||||
# provided).
|
||||
when false:
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkIdentDefs: IllFormedAst(a)
|
||||
var L = a.len
|
||||
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
|
||||
# ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
|
||||
# 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
|
||||
param.owner = fn
|
||||
addParamOrResult(c, param, fn.kind)
|
||||
|
||||
|
||||
maybeAddResult(c, fn, fn.ast)
|
||||
|
||||
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
||||
|
|
@ -132,9 +132,9 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
|||
closeScope(c)
|
||||
popInfoContext()
|
||||
|
||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
||||
{sfNoSideEffect, sfSideEffect}:
|
||||
{sfNoSideEffect, sfSideEffect}:
|
||||
localError(s.info, errXhasSideEffects, s.name.s)
|
||||
|
||||
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
|
||||
# proc signature could appear in the params:
|
||||
# proc foo[T](a: proc (x: T, b: type(x.y))
|
||||
#
|
||||
#
|
||||
# The solution would be to move this logic into semtypinst, but
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc.
|
||||
addDecl(c, prc)
|
||||
|
||||
|
||||
pushInfoContext(info)
|
||||
var cl = initTypeVars(c, pt, info)
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
|
||||
|
||||
for i in 1 .. <result.len:
|
||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||
if i > 1: resetIdTable(cl.symMap)
|
||||
|
|
@ -198,10 +198,10 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
|||
resetIdTable(cl.symMap)
|
||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||
result.n.sons[0] = originalParams[0].copyTree
|
||||
|
||||
|
||||
eraseVoidParams(result)
|
||||
skipIntLiteralParams(result)
|
||||
|
||||
|
||||
prc.typ = result
|
||||
maybeAddResult(c, prc, prc.ast)
|
||||
popInfoContext()
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
|||
if g.kind == skUnknown:
|
||||
var field: PSym = nil
|
||||
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)
|
||||
else:
|
||||
while ty != nil and ty.kind == tyObject:
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
|
||||
var enforceVoidContext = PType(kind: tyStmt)
|
||||
|
||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
||||
|
||||
|
||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1)
|
||||
|
|
@ -29,7 +29,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
|||
of nkIdent: s = lookUp(c, n.sons[0])
|
||||
of nkSym: s = n.sons[0].sym
|
||||
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)
|
||||
x.info = n.info
|
||||
incl(s.flags, sfUsed)
|
||||
|
|
@ -41,16 +41,16 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
|||
else:
|
||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||
localError(n.info, errInvalidControlFlowX,
|
||||
localError(n.info, errInvalidControlFlowX,
|
||||
renderTree(n, {renderNoComments}))
|
||||
|
||||
proc semAsm(con: PContext, n: PNode): PNode =
|
||||
proc semAsm(con: PContext, n: PNode): PNode =
|
||||
checkSonsLen(n, 2)
|
||||
var marker = pragmaAsm(con, n.sons[0])
|
||||
if marker == '\0': marker = '`' # default marker
|
||||
result = semAsmOrEmit(con, n, marker)
|
||||
|
||||
proc semWhile(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semWhile(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
|
|
@ -62,16 +62,16 @@ proc semWhile(c: PContext, n: PNode): PNode =
|
|||
if n.sons[1].typ == enforceVoidContext:
|
||||
result.typ = enforceVoidContext
|
||||
|
||||
proc toCover(t: PType): BiggestInt =
|
||||
proc toCover(t: PType): BiggestInt =
|
||||
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
||||
if t2.kind == tyEnum and enumHasHoles(t2):
|
||||
if t2.kind == tyEnum and enumHasHoles(t2):
|
||||
result = sonsLen(t2.n)
|
||||
else:
|
||||
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
||||
|
||||
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
||||
## Checks that the given symbol is a proper procedure variable, meaning
|
||||
## that it
|
||||
## that it
|
||||
var smoduleId = getModule(s).id
|
||||
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
||||
smoduleId != c.module.id:
|
||||
|
|
@ -98,11 +98,11 @@ proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
|
|||
localError(n.info, warnDestructor)
|
||||
# This still breaks too many things:
|
||||
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}:
|
||||
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])
|
||||
addSon(result, n)
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ const
|
|||
proc implicitlyDiscardable(n: PNode): bool =
|
||||
var n = n
|
||||
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
|
||||
|
||||
proc fixNilType(n: PNode) =
|
||||
|
|
@ -160,11 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
|
|||
while n.kind in skipForDiscardable: n = n.lastSon
|
||||
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
||||
|
||||
proc semIf(c: PContext, n: PNode): PNode =
|
||||
proc semIf(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var typ = commonTypeBegin
|
||||
var hasElse = false
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.len == 2:
|
||||
when newScopeForIf: openScope(c)
|
||||
|
|
@ -208,10 +208,10 @@ proc semCase(c: PContext, n: PNode): PNode =
|
|||
else:
|
||||
localError(n.info, errSelectorMustBeOfCertainTypes)
|
||||
return
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var x = n.sons[i]
|
||||
case x.kind
|
||||
of nkOfBranch:
|
||||
of nkOfBranch:
|
||||
checkMinSonsLen(x, 2)
|
||||
semCaseBranch(c, n, x, i, covered)
|
||||
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])
|
||||
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)
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||
changeType(result.sons[1], typ, check=true)
|
||||
result = result.sons[1]
|
||||
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
|
||||
|
||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||
if isTopLevel(c):
|
||||
if isTopLevel(c):
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||
incl(result.flags, sfGlobal)
|
||||
else:
|
||||
|
|
@ -340,14 +340,14 @@ proc checkNilable(v: PSym) =
|
|||
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||
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
|
||||
result = copyNode(n)
|
||||
var hasCompileTime = false
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
var a = n.sons[i]
|
||||
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)
|
||||
checkMinSonsLen(a, 3)
|
||||
var length = sonsLen(a)
|
||||
|
|
@ -369,7 +369,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
typ = def.typ
|
||||
else:
|
||||
# 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)
|
||||
#changeType(def.skipConv, typ, check=true)
|
||||
else:
|
||||
|
|
@ -381,15 +381,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
else:
|
||||
def = ast.emptyNode
|
||||
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
||||
|
||||
|
||||
# this can only happen for errornous var statements:
|
||||
if typ == nil: continue
|
||||
typeAllowedCheck(a.info, typ, symkind)
|
||||
var tup = skipTypes(typ, {tyGenericInst})
|
||||
if a.kind == nkVarTuple:
|
||||
if tup.kind != tyTuple:
|
||||
if a.kind == nkVarTuple:
|
||||
if tup.kind != tyTuple:
|
||||
localError(a.info, errXExpected, "tuple")
|
||||
elif length-2 != sonsLen(tup):
|
||||
elif length-2 != sonsLen(tup):
|
||||
localError(a.info, errWrongNumberOfVariables)
|
||||
else:
|
||||
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-1] = def
|
||||
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:
|
||||
message(a.info, warnEachIdentIsTuple)
|
||||
|
||||
for j in countup(0, length-3):
|
||||
var v = semIdentDef(c, a.sons[j], symkind)
|
||||
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)
|
||||
if shadowed != nil:
|
||||
shadowed.flags.incl(sfShadowed)
|
||||
if shadowed.kind == skResult:
|
||||
message(a.info, warnResultShadowed)
|
||||
# a shadowed variable is an error unless it appears on the right
|
||||
# side of the '=':
|
||||
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 hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
||||
|
||||
proc semConst(c: PContext, n: PNode): PNode =
|
||||
proc semConst(c: PContext, n: PNode): PNode =
|
||||
result = copyNode(n)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkConstDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
var v = semIdentDef(c, a.sons[0], skConst)
|
||||
|
|
@ -495,7 +498,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
|||
var iter = skipTypes(iterBase, {tyGenericInst})
|
||||
# length == 3 means that there is one for loop variable
|
||||
# and thus no tuple unpacking:
|
||||
if iter.kind != tyTuple or length == 3:
|
||||
if iter.kind != tyTuple or length == 3:
|
||||
if length == 3:
|
||||
var v = symForVar(c, n.sons[0])
|
||||
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 =
|
||||
result = newNodeI(nkCall, 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)
|
||||
else:
|
||||
result.add arg
|
||||
result = semExprNoDeref(c, result, {efWantIterator})
|
||||
|
||||
proc semFor(c: PContext, n: PNode): PNode =
|
||||
proc semFor(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 3)
|
||||
var length = sonsLen(n)
|
||||
|
|
@ -564,13 +567,13 @@ proc semFor(c: PContext, n: PNode): PNode =
|
|||
result.typ = enforceVoidContext
|
||||
closeScope(c)
|
||||
|
||||
proc semRaise(c: PContext, n: PNode): PNode =
|
||||
proc semRaise(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
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)
|
||||
|
||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||
|
|
@ -580,13 +583,13 @@ proc addGenericParamListToScope(c: PContext, n: PNode) =
|
|||
if a.kind == nkSym: addDecl(c, a.sym)
|
||||
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
|
||||
# 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]
|
||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind != nkTypeDef: illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
var s = semIdentDef(c, a.sons[0], skType)
|
||||
|
|
@ -599,29 +602,29 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
|||
a.sons[0] = newSymNode(s)
|
||||
|
||||
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]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||
checkSonsLen(a, 3)
|
||||
if (a.sons[0].kind != nkSym): illFormedAst(a)
|
||||
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)
|
||||
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,
|
||||
# symbol lookup needs to be done here.
|
||||
openScope(c)
|
||||
pushOwner(s)
|
||||
if s.magic == mNone: s.typ.kind = tyGenericBody
|
||||
# XXX for generic type aliases this is not correct! We need the
|
||||
# underlying Id really:
|
||||
# underlying Id really:
|
||||
#
|
||||
# type
|
||||
# TGObj[T] = object
|
||||
# TAlias[T] = TGObj[T]
|
||||
#
|
||||
#
|
||||
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
||||
a.sons[1] = s.typ.n
|
||||
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
|
||||
popOwner()
|
||||
closeScope(c)
|
||||
elif a.sons[2].kind != nkEmpty:
|
||||
elif a.sons[2].kind != nkEmpty:
|
||||
# process the type's body:
|
||||
pushOwner(s)
|
||||
var t = semTypeNode(c, a.sons[2], s.typ)
|
||||
if s.typ == nil:
|
||||
if s.typ == nil:
|
||||
s.typ = t
|
||||
elif t != s.typ:
|
||||
elif t != s.typ:
|
||||
# this can happen for e.g. tcan_alias_specialised_generic:
|
||||
assignType(s.typ, t)
|
||||
#debug s.typ
|
||||
|
|
@ -676,23 +679,23 @@ proc checkForMetaFields(n: PNode) =
|
|||
else:
|
||||
internalAssert false
|
||||
|
||||
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.kind == nkCommentStmt: continue
|
||||
if a.sons[0].kind != nkSym: illFormedAst(a)
|
||||
var s = a.sons[0].sym
|
||||
# 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}:
|
||||
# type aliases are hard:
|
||||
#MessageOut('for type ' + typeToString(s.typ));
|
||||
var t = semTypeNode(c, a.sons[2], nil)
|
||||
if t.kind in {tyObject, tyEnum}:
|
||||
if t.kind in {tyObject, tyEnum}:
|
||||
assignType(s.typ, t)
|
||||
s.typ.id = t.id # same id
|
||||
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)
|
||||
let aa = a.sons[2]
|
||||
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:
|
||||
localError(n.info, errGenerated, "invalid return type: 'stmt'")
|
||||
|
||||
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
|
||||
else: illFormedAst(n)
|
||||
|
||||
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
||||
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
||||
# search for the correct alias:
|
||||
var b = searchForBorrowProc(c, c.currentScope.parent, s)
|
||||
if b != nil:
|
||||
if b != nil:
|
||||
# store the alias:
|
||||
n.sons[bodyPos] = newSymNode(b)
|
||||
else:
|
||||
localError(n.info, errNoSymbolToBorrowFromFound)
|
||||
|
||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||
localError(n.info, errNoSymbolToBorrowFromFound)
|
||||
|
||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||
if t != nil:
|
||||
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
|
||||
s.typ = t
|
||||
|
|
@ -742,7 +745,7 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
|||
addParamOrResult(c, s, owner)
|
||||
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))
|
||||
|
||||
proc copyExcept(n: PNode, i: int): PNode =
|
||||
|
|
@ -786,7 +789,8 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
|||
result = semStmt(c, x)
|
||||
# since a proc annotation can set pragmas, we process these here again.
|
||||
# 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)
|
||||
return
|
||||
|
||||
|
|
@ -807,7 +811,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
pushOwner(s)
|
||||
openScope(c)
|
||||
var gp: PNode
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||
gp = n.sons[genericParamsPos]
|
||||
else:
|
||||
|
|
@ -857,13 +861,13 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
|
||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
var n = n
|
||||
|
||||
|
||||
n = replaceTypesInBody(c, pt, n)
|
||||
result = n
|
||||
|
||||
|
||||
n.sons[genericParamsPos] = emptyNode
|
||||
n.sons[paramsPos] = n.typ.n
|
||||
|
||||
|
||||
openScope(c)
|
||||
var s = n.sons[namePos].sym
|
||||
pushOwner(s)
|
||||
|
|
@ -876,7 +880,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
|||
popProcCon(c)
|
||||
popOwner()
|
||||
closeScope(c)
|
||||
|
||||
|
||||
s.ast = result
|
||||
|
||||
# alternative variant (not quite working):
|
||||
|
|
@ -922,7 +926,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
|||
else: break
|
||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||
if t.deepCopy.isNil: t.deepCopy = s
|
||||
else:
|
||||
else:
|
||||
localError(n.info, errGenerated,
|
||||
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
||||
else:
|
||||
|
|
@ -989,10 +993,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
pushOwner(s)
|
||||
openScope(c)
|
||||
var gp: PNode
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||
gp = n.sons[genericParamsPos]
|
||||
else:
|
||||
else:
|
||||
gp = newNodeI(nkGenericParams, n.info)
|
||||
# process parameters:
|
||||
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])
|
||||
if s.kind in skIterators:
|
||||
s.typ.flags.incl(tfIterator)
|
||||
|
||||
|
||||
var proto = searchForProc(c, s.scope, s)
|
||||
if proto == nil:
|
||||
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
||||
|
|
@ -1027,14 +1031,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
|||
else:
|
||||
implicitPragmas(c, s, n, validPragmas)
|
||||
else:
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
||||
if sfForward notin proto.flags:
|
||||
if sfForward notin proto.flags:
|
||||
wrongRedefinition(n.info, proto.name.s)
|
||||
excl(proto.flags, sfForward)
|
||||
closeScope(c) # close scope with wrong 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])
|
||||
addParams(c, proto.typ.n, proto.kind)
|
||||
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
|
||||
else:
|
||||
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)
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||
sideEffectsCheck(c, s)
|
||||
|
|
@ -1122,14 +1126,14 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
|||
else:
|
||||
s.typ.callConv = ccInline
|
||||
when false:
|
||||
if s.typ.callConv != ccInline:
|
||||
if s.typ.callConv != ccInline:
|
||||
s.typ.callConv = ccClosure
|
||||
# and they always at least use the 'env' for the state field:
|
||||
incl(s.typ.flags, tfCapturesEnv)
|
||||
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
||||
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)
|
||||
|
||||
proc hasObjParam(s: PSym): bool =
|
||||
|
|
@ -1142,10 +1146,10 @@ proc finishMethod(c: PContext, s: PSym) =
|
|||
if hasObjParam(s):
|
||||
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")
|
||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||
|
||||
|
||||
var s = result.sons[namePos].sym
|
||||
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
||||
if hasObjParam(s):
|
||||
|
|
@ -1153,7 +1157,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
|||
else:
|
||||
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")
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
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")
|
||||
addConverter(c, s)
|
||||
|
||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
result = semProcAux(c, n, skMacro, macroPragmas)
|
||||
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 n.sons[bodyPos].kind == nkEmpty:
|
||||
localError(n.info, errImplOfXexpected, s.name.s)
|
||||
|
||||
|
||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
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])
|
||||
if f != InvalidFileIDX:
|
||||
if containsOrIncl(c.includedFiles, f):
|
||||
if containsOrIncl(c.includedFiles, f):
|
||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||
else:
|
||||
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
||||
excl(c.includedFiles, f)
|
||||
|
||||
|
||||
proc setLine(n: PNode, info: TLineInfo) =
|
||||
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
||||
n.info = info
|
||||
|
||||
|
||||
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||
let pragmaList = n.sons[0]
|
||||
pragma(c, nil, pragmaList, exprPragmas)
|
||||
|
|
@ -1196,7 +1200,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
|||
for i in 0 .. <pragmaList.len:
|
||||
case whichPragma(pragmaList.sons[i])
|
||||
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||
of wLocks:
|
||||
of wLocks:
|
||||
result = n
|
||||
result.typ = n.sons[1].typ
|
||||
else: discard
|
||||
|
|
@ -1311,8 +1315,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
inner.addSon(semStmtList(c, rest, flags))
|
||||
n.sons.setLen(i+1)
|
||||
return
|
||||
of LastBlockStmts:
|
||||
for j in countup(i + 1, length - 1):
|
||||
of LastBlockStmts:
|
||||
for j in countup(i + 1, length - 1):
|
||||
case n.sons[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||
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 " &
|
||||
# "is discardable or discarded")
|
||||
|
||||
proc semStmt(c: PContext, n: PNode): PNode =
|
||||
proc semStmt(c: PContext, n: PNode): PNode =
|
||||
# now: simply an alias:
|
||||
result = semExprNoType(c, n)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
# this module does the semantic checking of type declarations
|
||||
# included from sem.nim
|
||||
|
||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||
if prev == nil:
|
||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||
if prev == nil:
|
||||
result = newTypeS(kind, c)
|
||||
else:
|
||||
else:
|
||||
result = prev
|
||||
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.addSonSkipIntLit(newTypeS(k, c))
|
||||
|
||||
|
|
@ -32,22 +32,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = newOrPrevType(tyEnum, prev, c)
|
||||
result.n = newNodeI(nkEnumTy, n.info)
|
||||
checkMinSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
base = semTypeNode(c, n.sons[0].sons[0], nil)
|
||||
if base.kind != tyEnum:
|
||||
if base.kind != tyEnum:
|
||||
localError(n.sons[0].info, errInheritanceOnlyWithEnums)
|
||||
counter = lastOrd(base) + 1
|
||||
rawAddSon(result, base)
|
||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||
var hasNull = false
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkEnumFieldDef:
|
||||
of nkEnumFieldDef:
|
||||
e = newSymS(skEnumField, n.sons[i].sons[0], c)
|
||||
var v = semConstExpr(c, n.sons[i].sons[1])
|
||||
var strVal: PNode = nil
|
||||
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyTuple:
|
||||
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyTuple:
|
||||
if sonsLen(v) == 2:
|
||||
strVal = v.sons[1] # second tuple part is the string value
|
||||
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)
|
||||
if i != 1:
|
||||
if x != counter: incl(result.flags, tfEnumHasHoles)
|
||||
if x < counter:
|
||||
if x < counter:
|
||||
localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
|
||||
x = counter
|
||||
e.ast = strVal # might be nil
|
||||
counter = x
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
e = n.sons[i].sym
|
||||
of nkIdent, nkAccQuoted:
|
||||
of nkIdent, nkAccQuoted:
|
||||
e = newSymS(skEnumField, n.sons[i], c)
|
||||
else:
|
||||
illFormedAst(n[i])
|
||||
|
|
@ -87,28 +87,28 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
|||
inc(counter)
|
||||
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)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
if base.kind == tyGenericInst: base = lastSon(base)
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
if not isOrdinalType(base):
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif lengthOrd(base) > MaxSetElements:
|
||||
elif lengthOrd(base) > MaxSetElements:
|
||||
localError(n.info, errSetTooBig)
|
||||
else:
|
||||
localError(n.info, errXExpectsOneTypeParam, "set")
|
||||
addSonSkipIntLit(result, errorType(c))
|
||||
|
||||
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||
prev: PType): PType =
|
||||
|
||||
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||
prev: PType): PType =
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
else:
|
||||
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
||||
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)
|
||||
addSonSkipIntLit(result, base)
|
||||
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 1:
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 1:
|
||||
result = newOrPrevType(tyVar, prev, c)
|
||||
var base = semTypeNode(c, n.sons[0], nil)
|
||||
if base.kind == tyVar:
|
||||
if base.kind == tyVar:
|
||||
localError(n.info, errVarVarTypeNotAllowed)
|
||||
base = base.sons[0]
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
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)
|
||||
result = newOrPrevType(tyDistinct, prev, c)
|
||||
addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
|
||||
if n.len > 1: result.n = n[1]
|
||||
|
||||
|
||||
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
assert isRange(n)
|
||||
checkSonsLen(n, 3)
|
||||
|
|
@ -164,11 +164,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
|||
result.n = newNodeI(nkRange, n.info)
|
||||
if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
|
||||
localError(n.info, errRangeIsEmpty)
|
||||
|
||||
|
||||
var range: array[2, PNode]
|
||||
range[0] = semExprWithType(c, n[1], {efDetermineType})
|
||||
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
||||
|
||||
|
||||
var rangeT: array[2, PType]
|
||||
for i in 0..1:
|
||||
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)
|
||||
elif enumHasHoles(rangeT[0]):
|
||||
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
||||
|
||||
|
||||
for i in 0..1:
|
||||
if hasGenericArguments(range[i]):
|
||||
result.n.addSon makeStaticExpr(c, range[i])
|
||||
else:
|
||||
result.n.addSon semConstExpr(c, range[i])
|
||||
|
||||
|
||||
if weakLeValue(result.n[0], result.n[1]) == impNo:
|
||||
localError(n.info, errRangeIsEmpty)
|
||||
|
||||
|
|
@ -201,10 +201,10 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
|||
incl(result.flags, tfNeedsInit)
|
||||
elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
|
||||
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:
|
||||
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:
|
||||
incl(result.flags, tfNeedsInit)
|
||||
else:
|
||||
|
|
@ -243,13 +243,13 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
|||
else:
|
||||
let x = semConstExpr(c, e)
|
||||
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}))
|
||||
else:
|
||||
result = x.typ.skipTypes({tyTypeDesc})
|
||||
#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
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
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 not isOrdinalType(indx):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(indx):
|
||||
elif enumHasHoles(indx):
|
||||
localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
|
||||
base = semTypeNode(c, n.sons[2], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
else:
|
||||
localError(n.info, errArrayExpectsTwoTypeParams)
|
||||
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)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
|
|
@ -281,7 +281,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
if n.kind == nkSym:
|
||||
if n.kind == nkSym:
|
||||
result = n.sym
|
||||
else:
|
||||
when defined(nimfix):
|
||||
|
|
@ -307,7 +307,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
|||
result = result.typ.sym.copySym
|
||||
result.typ = copyType(result.typ, result.typ.owner, true)
|
||||
result.typ.flags.incl tfUnresolved
|
||||
|
||||
|
||||
if result.kind == skGenericParam:
|
||||
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
|
||||
tfWildcard in result.typ.flags:
|
||||
|
|
@ -319,7 +319,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
|||
localError(n.info, errTypeExpected)
|
||||
return errorSym(c, n)
|
||||
|
||||
if result.kind != skType:
|
||||
if result.kind != skType:
|
||||
# this implements the wanted ``var v: V, x: V`` feature ...
|
||||
var ov: TOverloadIter
|
||||
var amb = initOverloadIter(ov, c, n)
|
||||
|
|
@ -344,48 +344,54 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
|||
else:
|
||||
localError(n.info, errIdentifierExpected)
|
||||
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 =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
||||
var typ: PType
|
||||
result = newOrPrevType(tyTuple, prev, c)
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
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)
|
||||
else:
|
||||
localError(a.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
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)
|
||||
field.typ = typ
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
if containsOrIncl(check, field.name.id):
|
||||
if containsOrIncl(check, field.name.id):
|
||||
localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
|
||||
else:
|
||||
addSon(result.n, newSymNode(field))
|
||||
addSonSkipIntLit(result, typ)
|
||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
# identifier with visibility
|
||||
if n.kind == nkPostfix:
|
||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||
if n.kind == nkPostfix:
|
||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||
# for gensym'ed identifiers the identifier may already have been
|
||||
# transformed to a symbol and we need to use that here:
|
||||
result = newSymG(kind, n.sons[1], c)
|
||||
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)
|
||||
else:
|
||||
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
||||
|
|
@ -393,7 +399,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
|||
illFormedAst(n)
|
||||
else:
|
||||
result = newSymG(kind, n, c)
|
||||
|
||||
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
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) =
|
||||
let ex = t[branchIndex][currentEx].skipConv
|
||||
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 overlap(t.sons[i].sons[j].skipConv, ex):
|
||||
localError(ex.info, errDuplicateCaseLabel)
|
||||
|
||||
|
||||
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
|
||||
checkMinSonsLen(t, 1)
|
||||
let ac = semConstExpr(c, a)
|
||||
let bc = semConstExpr(c, b)
|
||||
let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
|
||||
let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
|
||||
|
||||
|
||||
result = newNodeI(nkRange, a.info)
|
||||
result.add(at)
|
||||
result.add(bt)
|
||||
if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
|
||||
else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
|
||||
|
||||
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
checkSonsLen(b, 3)
|
||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||
|
||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
if isRange(b):
|
||||
checkSonsLen(b, 3)
|
||||
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)
|
||||
inc(covered)
|
||||
|
||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
covered: var BiggestInt) =
|
||||
|
||||
for i in countup(0, sonsLen(branch) - 2):
|
||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
covered: var BiggestInt) =
|
||||
|
||||
for i in countup(0, sonsLen(branch) - 2):
|
||||
var b = branch.sons[i]
|
||||
if b.kind == nkRange:
|
||||
branch.sons[i] = b
|
||||
|
|
@ -480,7 +486,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
|||
var L = branch.len
|
||||
swap(branch.sons[L-2], branch.sons[L-1])
|
||||
checkForOverlap(c, t, i, branchIndex)
|
||||
|
||||
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType)
|
||||
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)
|
||||
delSon(b, sonsLen(b) - 1)
|
||||
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)
|
||||
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) =
|
||||
if n == nil: return
|
||||
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)
|
||||
of nkRecCase:
|
||||
semRecordCase(c, n, check, pos, father, rectype)
|
||||
of nkNilLit:
|
||||
of nkNilLit:
|
||||
if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
|
||||
of nkRecList:
|
||||
# attempt to keep the nesting at a sane level:
|
||||
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)
|
||||
if a != father: addSon(father, a)
|
||||
of nkIdentDefs:
|
||||
|
|
@ -570,10 +576,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
|||
var a: PNode
|
||||
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
|
||||
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)
|
||||
var typ: PType
|
||||
if n.sons[length-2].kind == nkEmpty:
|
||||
if n.sons[length-2].kind == nkEmpty:
|
||||
localError(n.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
else:
|
||||
|
|
@ -586,7 +592,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
|||
f.typ = typ
|
||||
f.position = pos
|
||||
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.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
|
||||
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)
|
||||
of nkEmpty: discard
|
||||
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) =
|
||||
case n.kind
|
||||
of nkRecCase:
|
||||
|
|
@ -618,31 +624,31 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
|||
inc(pos)
|
||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||
|
||||
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||
result = t
|
||||
if result.kind == tyGenericInvocation:
|
||||
result = result.sons[0]
|
||||
if result.kind == tyGenericBody:
|
||||
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) =
|
||||
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)
|
||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
||||
var check = initIntSet()
|
||||
var pos = 0
|
||||
var pos = 0
|
||||
var base: PType = nil
|
||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||
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)
|
||||
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)
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
|
|
@ -723,7 +729,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
genericParams.addSon(newSymNode(s))
|
||||
result = typeClass
|
||||
addDecl(c, s)
|
||||
|
||||
|
||||
# XXX: There are codegen errors if this is turned into a nested proc
|
||||
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
||||
|
|
@ -742,7 +748,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
case paramType.kind:
|
||||
of tyAnything:
|
||||
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||
|
||||
|
||||
of tyStatic:
|
||||
# proc(a: expr{string}, b: expr{nkLambda})
|
||||
# overload on compile time values and AST trees
|
||||
|
|
@ -753,7 +759,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
|
||||
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
|
||||
result.flags.incl({tfHasStatic, tfUnresolved})
|
||||
|
||||
|
||||
of tyTypeDesc:
|
||||
if tfUnresolved notin paramType.flags:
|
||||
# naked typedescs are not bindOnce types
|
||||
|
|
@ -761,12 +767,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
paramTypId.id == typedescId.id: paramTypId = nil
|
||||
result = addImplicitGeneric(
|
||||
c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
|
||||
|
||||
|
||||
of tyDistinct:
|
||||
if paramType.sonsLen == 1:
|
||||
# disable the bindOnce behavior for the type class
|
||||
result = liftingWalk(paramType.sons[0], true)
|
||||
|
||||
|
||||
of tySequence, tySet, tyArray, tyOpenArray,
|
||||
tyVar, tyPtr, tyRef, tyProc:
|
||||
# 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:
|
||||
paramType.sons[i] = lifted
|
||||
result = paramType
|
||||
|
||||
|
||||
of tyGenericBody:
|
||||
result = newTypeS(tyGenericInvocation, c)
|
||||
result.rawAddSon(paramType)
|
||||
|
||||
|
||||
for i in 0 .. paramType.sonsLen - 2:
|
||||
if paramType.sons[i].kind == tyStatic:
|
||||
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
|
||||
else:
|
||||
result.rawAddSon newTypeS(tyAnything, c)
|
||||
|
||||
|
||||
if paramType.lastSon.kind == tyUserTypeClass:
|
||||
result.kind = tyUserTypeClassInst
|
||||
result.rawAddSon paramType.lastSon
|
||||
return addImplicitGeneric(result)
|
||||
|
||||
|
||||
result = instGenericContainer(c, paramType.sym.info, result,
|
||||
allowMetaTypes = true)
|
||||
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
|
||||
|
|
@ -832,7 +838,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
if liftBody != nil:
|
||||
result = liftBody
|
||||
result.shouldHaveMeta
|
||||
|
||||
|
||||
of tyGenericInvocation:
|
||||
for i in 1 .. <paramType.sonsLen:
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
|
|
@ -844,18 +850,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
|
||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||
|
||||
|
||||
of tyExpr:
|
||||
if procKind notin {skMacro, skTemplate}:
|
||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
||||
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(info, paramType.sym)
|
||||
styleCheckUse(info, paramType.sym)
|
||||
if tfWildcard in paramType.flags:
|
||||
paramType.flags.excl tfWildcard
|
||||
paramType.sym.kind = skType
|
||||
|
||||
|
||||
else: discard
|
||||
|
||||
# result = liftingWalk(paramType)
|
||||
|
|
@ -872,7 +878,7 @@ proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
|
|||
result.callConv = lastOptionEntry(c).defaultCC
|
||||
result.n = newNodeI(nkFormalParams, info)
|
||||
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
|
||||
# usual we desperately try to save memory:
|
||||
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)
|
||||
|
||||
if hasDefault:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
# check type compatibility between def.typ and typ:
|
||||
if typ == nil:
|
||||
typ = def.typ
|
||||
|
|
@ -927,7 +933,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
typ = newTypeS(tdef, c)
|
||||
|
||||
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)
|
||||
let lifted = liftParamType(c, kind, genericParams, typ,
|
||||
arg.name.s, arg.info)
|
||||
|
|
@ -937,7 +943,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
arg.constraint = constraint
|
||||
inc(counter)
|
||||
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)
|
||||
addSon(result.n, newSymNode(arg))
|
||||
rawAddSon(result, finalType)
|
||||
|
|
@ -950,9 +956,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
|||
elif kind == skIterator:
|
||||
# XXX This is special magic we should likely get rid of
|
||||
r = newTypeS(tyExpr, c)
|
||||
|
||||
|
||||
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':
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
# '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
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
inc(c.p.nestedBlockCounter)
|
||||
checkSonsLen(n, 2)
|
||||
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" %
|
||||
[s.name.s, ($s.kind).substr(2).toLower])
|
||||
return newOrPrevType(tyError, prev, c)
|
||||
|
||||
|
||||
var t = s.typ
|
||||
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
||||
t = t.base
|
||||
|
|
@ -1036,7 +1042,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
|||
else:
|
||||
var m = newCandidate(c, t)
|
||||
matches(c, n, copyTree(n), m)
|
||||
|
||||
|
||||
if m.state != csMatch:
|
||||
var err = "cannot instantiate " & typeToString(t) & "\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)
|
||||
|
||||
var isConcrete = true
|
||||
|
||||
|
||||
for i in 1 .. <m.call.len:
|
||||
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
||||
if containsGenericType(typ): isConcrete = false
|
||||
addToResult(typ)
|
||||
|
||||
|
||||
if isConcrete:
|
||||
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
|
||||
# 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
|
||||
pragmas = n[1]
|
||||
inherited = n[2]
|
||||
|
||||
|
||||
if inherited.kind != nkEmpty:
|
||||
for n in inherited.sons:
|
||||
let typ = semTypeNode(c, n, nil)
|
||||
|
|
@ -1114,12 +1120,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
checkSonsLen(n, 1)
|
||||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
||||
result = typExpr.typ.skipTypes({tyIter})
|
||||
of nkPar:
|
||||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else:
|
||||
# XXX support anon tuple here
|
||||
localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
result = semAnonTuple(c, n, prev)
|
||||
of nkCallKinds:
|
||||
if isRange(n):
|
||||
result = semRangeAux(c, n, prev)
|
||||
|
|
@ -1197,7 +1201,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
||||
of nkIdent, nkAccQuoted:
|
||||
var s = semTypeIdent(c, n)
|
||||
if s.typ == nil:
|
||||
if s.typ == nil:
|
||||
if s.kind != skError: localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
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
|
||||
elif prev == nil:
|
||||
result = s.typ
|
||||
else:
|
||||
else:
|
||||
assignType(prev, s.typ)
|
||||
# bugfix: keep the fresh id for aliases to integral types:
|
||||
if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64}:
|
||||
tyUInt..tyUInt64}:
|
||||
prev.id = s.typ.id
|
||||
result = prev
|
||||
of nkSym:
|
||||
if n.sym.kind == skType and n.sym.typ != nil:
|
||||
var t = n.sym.typ
|
||||
if prev == nil:
|
||||
if prev == nil:
|
||||
result = t
|
||||
else:
|
||||
else:
|
||||
assignType(prev, t)
|
||||
result = prev
|
||||
markUsed(n.info, n.sym)
|
||||
|
|
@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||
of nkTupleTy: result = semTuple(c, n, prev)
|
||||
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||
of nkRefTy: result = semAnyRef(c, n, tyRef, 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)
|
||||
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.align = size.int16
|
||||
m.typ.size = size
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
case m.magic
|
||||
of mInt: setMagicType(m, tyInt, intSize)
|
||||
of mInt8: setMagicType(m, tyInt8, 1)
|
||||
|
|
@ -1290,21 +1295,21 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
of mFloat128: setMagicType(m, tyFloat128, 16)
|
||||
of mBool: setMagicType(m, tyBool, 1)
|
||||
of mChar: setMagicType(m, tyChar, 1)
|
||||
of mString:
|
||||
of mString:
|
||||
setMagicType(m, tyString, ptrSize)
|
||||
rawAddSon(m.typ, getSysType(tyChar))
|
||||
of mCstring:
|
||||
of mCstring:
|
||||
setMagicType(m, tyCString, ptrSize)
|
||||
rawAddSon(m.typ, getSysType(tyChar))
|
||||
of mPointer: setMagicType(m, tyPointer, ptrSize)
|
||||
of mEmptySet:
|
||||
of mEmptySet:
|
||||
setMagicType(m, tySet, 1)
|
||||
rawAddSon(m.typ, newTypeS(tyEmpty, c))
|
||||
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||
of mExpr: setMagicType(m, tyExpr, 0)
|
||||
of mStmt: setMagicType(m, tyStmt, 0)
|
||||
of mTypeDesc:
|
||||
of mTypeDesc:
|
||||
setMagicType(m, tyTypeDesc, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mVoidType: setMagicType(m, tyEmpty, 0)
|
||||
|
|
@ -1318,8 +1323,8 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
setMagicType(m, tyRange, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mSet:
|
||||
setMagicType(m, tySet, 0)
|
||||
of mSeq:
|
||||
setMagicType(m, tySet, 0)
|
||||
of mSeq:
|
||||
setMagicType(m, tySequence, 0)
|
||||
of mOrdinal:
|
||||
setMagicType(m, tyOrdinal, 0)
|
||||
|
|
@ -1335,13 +1340,13 @@ proc processMagicType(c: PContext, m: PSym) =
|
|||
incl m.typ.flags, tfShared
|
||||
rawAddSon(m.typ, sysTypeFromName"shared")
|
||||
else: localError(m.info, errTypeExpected)
|
||||
|
||||
|
||||
proc semGenericConstraints(c: PContext, x: PType): PType =
|
||||
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)
|
||||
if n.kind != nkGenericParams:
|
||||
if n.kind != nkGenericParams:
|
||||
illFormedAst(n)
|
||||
return
|
||||
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}
|
||||
let constraint = a{-2}
|
||||
var typ: PType
|
||||
|
||||
|
||||
if constraint.kind != nkEmpty:
|
||||
typ = semTypeNode(c, constraint, nil)
|
||||
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)])
|
||||
else:
|
||||
typ = semGenericConstraints(c, typ)
|
||||
|
||||
|
||||
if def.kind != nkEmpty:
|
||||
def = semConstExpr(c, def)
|
||||
if typ == nil:
|
||||
|
|
@ -1372,7 +1377,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
|||
def.typ = def.typ.skipTypes({tyTypeDesc})
|
||||
if not containsGenericType(def.typ):
|
||||
def = fitNode(c, typ, def)
|
||||
|
||||
|
||||
if typ == nil:
|
||||
typ = newTypeS(tyGenericParam, c)
|
||||
if father == nil: typ.flags.incl tfWildcard
|
||||
|
|
|
|||
|
|
@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
|
|||
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||
# This is meant for objects and tuples
|
||||
# The type must be fully instantiated!
|
||||
if n.isNil:
|
||||
return
|
||||
internalAssert n.kind != nkRecWhen
|
||||
case n.kind
|
||||
of nkSym:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
## This module implements the signature matching for resolving
|
||||
## the call to overloaded procs, generic procs and operators.
|
||||
|
||||
import
|
||||
import
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
||||
nimfix.pretty
|
||||
|
|
@ -19,7 +19,7 @@ when not defined(noDocgen):
|
|||
import docgen
|
||||
|
||||
type
|
||||
TCandidateState* = enum
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
CandidateErrors* = seq[PSym]
|
||||
|
|
@ -62,10 +62,10 @@ type
|
|||
isGeneric,
|
||||
isFromIntLit, # conversion *from* int literal; proven safe
|
||||
isEqual
|
||||
|
||||
|
||||
const
|
||||
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
||||
|
||||
|
||||
proc markUsed*(info: TLineInfo, s: PSym)
|
||||
|
||||
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 =
|
||||
initCandidate(ctx, result, callee)
|
||||
|
||||
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||
a.c = b.c
|
||||
a.exactMatches = b.exactMatches
|
||||
a.subtypeMatches = b.subtypeMatches
|
||||
|
|
@ -157,17 +157,40 @@ proc sumGeneric(t: PType): int =
|
|||
result = ord(t.kind == tyGenericInvocation)
|
||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||
break
|
||||
of tyProc:
|
||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
||||
return 1
|
||||
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
|
||||
|
||||
#var ggDebug: bool
|
||||
|
||||
proc complexDisambiguation(a, b: PType): int =
|
||||
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
|
||||
# 'a' matches better if *every* argument matches better or equal than 'b'.
|
||||
var winner = 0
|
||||
for i in 1 .. <min(a.len, b.len):
|
||||
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:
|
||||
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
|
||||
var a = a
|
||||
var b = b
|
||||
|
||||
|
||||
if aa < bb: swap(a, b)
|
||||
# all must be better
|
||||
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:
|
||||
result = complexDisambiguation(a.callee, b.callee)
|
||||
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
writeln(stdout, "exact matches: " & $c.exactMatches)
|
||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||
writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
|
|
@ -225,7 +248,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
|||
result = ""
|
||||
for i in countup(startIdx, n.len - 1):
|
||||
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, ": ")
|
||||
if arg.typ.isNil:
|
||||
|
|
@ -241,9 +264,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
|||
if i != sonsLen(n) - 1: add(result, ", ")
|
||||
|
||||
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
|
||||
of tyArrayConstr:
|
||||
of tyArrayConstr:
|
||||
# make it an array
|
||||
result = newType(tyArray, t.owner)
|
||||
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
|
||||
of tyGenericParam, tyAnything:
|
||||
result = t
|
||||
while true:
|
||||
while true:
|
||||
result = PType(idTableGet(c.bindings, t))
|
||||
if result == nil:
|
||||
break # it's ok, no match
|
||||
|
|
@ -267,15 +290,15 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
|||
result = t
|
||||
else:
|
||||
result = t # Note: empty is valid here
|
||||
|
||||
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
if a.kind == f.kind:
|
||||
|
||||
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||
if a.kind == f.kind:
|
||||
result = isEqual
|
||||
else:
|
||||
let ab = skipTypes(a, {tyRange})
|
||||
let k = ab.kind
|
||||
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
|
||||
isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
|
||||
ab.n.intVal <= lastOrd(f):
|
||||
|
|
@ -286,7 +309,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
|||
result = isIntConv
|
||||
elif k >= min and k <= max:
|
||||
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
|
||||
a.n[0].intVal >= firstOrd(f) and
|
||||
a.n[1].intVal <= lastOrd(f):
|
||||
|
|
@ -318,12 +341,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
|||
if f.kind == tyFloat32: result = isConvertible
|
||||
else: result = isIntConv
|
||||
else: result = isNone
|
||||
|
||||
|
||||
proc isObjectSubtype(a, f: PType): int =
|
||||
var t = a
|
||||
assert t.kind == tyObject
|
||||
var depth = 0
|
||||
while t != nil and not sameObjectTypes(f, t):
|
||||
while t != nil and not sameObjectTypes(f, t):
|
||||
assert t.kind == tyObject
|
||||
t = t.sons[0]
|
||||
if t == nil: break
|
||||
|
|
@ -332,17 +355,18 @@ proc isObjectSubtype(a, f: PType): int =
|
|||
if t != nil:
|
||||
result = depth
|
||||
|
||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||
if a <= b: result = a
|
||||
else: result = b
|
||||
|
||||
|
||||
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
result = isNone
|
||||
if sameType(f, a): result = isEqual
|
||||
if sameType(f, a):
|
||||
result = isEqual
|
||||
elif sonsLen(a) == sonsLen(f):
|
||||
result = isEqual
|
||||
let firstField = if f.kind == tyTuple: 0
|
||||
else: 1
|
||||
else: 1
|
||||
for i in countup(firstField, sonsLen(f) - 1):
|
||||
var m = typeRel(c, f.sons[i], a.sons[i])
|
||||
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)
|
||||
# to another generic type appearing in the proc
|
||||
# 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
|
||||
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
|
||||
if f == nil or f.isMetaType:
|
||||
# no luck resolving the type, so the inference fails
|
||||
return isNone
|
||||
let reverseRel = typeRel(c, a, f)
|
||||
if reverseRel == isGeneric:
|
||||
if reverseRel >= isGeneric:
|
||||
result = isInferred
|
||||
inc c.genericMatches
|
||||
#inc c.genericMatches
|
||||
else:
|
||||
result = typeRel(c, f, a)
|
||||
|
||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||
result = isNone
|
||||
|
||||
if result == isEqual:
|
||||
inc c.exactMatches
|
||||
|
||||
|
||||
#if result == isEqual:
|
||||
# inc c.exactMatches
|
||||
|
||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
case a.kind
|
||||
of tyProc:
|
||||
if sonsLen(f) != sonsLen(a): return
|
||||
result = isEqual # start with maximum; also correct for no
|
||||
# params at all
|
||||
|
||||
|
||||
template checkParam(f, a) =
|
||||
result = minRel(result, procParamTypeRel(c, f, a))
|
||||
if result == isNone: return
|
||||
|
|
@ -407,7 +431,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
# return type!
|
||||
for i in 1 .. <f.sonsLen:
|
||||
checkParam(f.sons[i], a.sons[i])
|
||||
|
||||
|
||||
if f.sons[0] != nil:
|
||||
if a.sons[0] != nil:
|
||||
checkParam(f.sons[0], a.sons[0])
|
||||
|
|
@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
return isNone
|
||||
when useEffectSystem:
|
||||
if not compatibleEffects(f, a): return isNone
|
||||
|
||||
of tyNil:
|
||||
result = f.allowsNil
|
||||
of tyIter:
|
||||
|
|
@ -487,14 +512,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
else:
|
||||
param = paramSym skType
|
||||
param.typ = makeTypeDesc(c, typ)
|
||||
|
||||
|
||||
addDecl(c, param)
|
||||
|
||||
for param in body.n[0]:
|
||||
var
|
||||
dummyName: PNode
|
||||
dummyType: PType
|
||||
|
||||
|
||||
if param.kind == nkVarTy:
|
||||
dummyName = param[0]
|
||||
dummyType = if a.kind != tyVar: makeVarType(c, a)
|
||||
|
|
@ -520,7 +545,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
of nkTypeSection: discard
|
||||
of nkConstDef: discard
|
||||
else: discard
|
||||
|
||||
|
||||
return isGeneric
|
||||
|
||||
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:
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
assert(f != nil)
|
||||
|
||||
|
||||
if f.kind == tyExpr:
|
||||
if aOrig != nil: put(c.bindings, f, aOrig)
|
||||
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`
|
||||
# for example, but unfortunately `prepareOperand` is not called in certain
|
||||
# situation when nkDotExpr are rotated to nkDotCalls
|
||||
|
||||
|
||||
if a.kind == tyGenericInst and
|
||||
skipTypes(f, {tyVar}).kind notin {
|
||||
tyGenericBody, tyGenericInvocation,
|
||||
|
|
@ -590,10 +615,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
return typeRel(c, f, lastSon(a))
|
||||
|
||||
template bindingRet(res) =
|
||||
when res == isGeneric:
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
if doBind: put(c.bindings, f, bound)
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
if doBind: put(c.bindings, f, bound)
|
||||
return res
|
||||
|
||||
template considerPreviousT(body: stmt) {.immediate.} =
|
||||
|
|
@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyOr:
|
||||
# seq[int|string] vs seq[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:
|
||||
if typeRel(c, f, branch, false) == isNone:
|
||||
return isNone
|
||||
|
||||
return isGeneric
|
||||
let x = typeRel(c, f, branch, false)
|
||||
if x == isNone: return isNone
|
||||
if x < result: result = x
|
||||
|
||||
of tyAnd:
|
||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||
# only one match is enough
|
||||
for branch in a.sons:
|
||||
if typeRel(c, f, branch, false) != isNone:
|
||||
return isGeneric
|
||||
|
||||
return isNone
|
||||
let x = typeRel(c, f, branch, false)
|
||||
if x != isNone:
|
||||
return if x >= isGeneric: isGeneric else: x
|
||||
result = isNone
|
||||
|
||||
of tyNot:
|
||||
case f.kind
|
||||
|
|
@ -626,9 +651,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
# seq[!int] vs seq[!number]
|
||||
# seq[float] matches the first, but not the second
|
||||
# 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)
|
||||
|
||||
|
||||
else:
|
||||
# negative type classes are essentially infinite,
|
||||
# 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:
|
||||
result = typeRel(c, base(f), base(a))
|
||||
if result < isGeneric: result = isNone
|
||||
of tyArrayConstr:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||
of tyArrayConstr:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||
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
|
||||
of tyArray:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||
of tyArray:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||
result = isSubtype
|
||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
||||
result = isConvertible
|
||||
of tySequence:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||
of tySequence:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||
result = isConvertible
|
||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
||||
result = isConvertible
|
||||
else: discard
|
||||
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 tyNil:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
of tyTuple:
|
||||
of tyTuple:
|
||||
if a.kind == tyTuple: result = recordRel(c, f, a)
|
||||
of tyObject:
|
||||
if a.kind == tyObject:
|
||||
|
|
@ -781,15 +806,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
inc(c.inheritancePenalty, depth)
|
||||
result = isSubtype
|
||||
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)
|
||||
of tySet:
|
||||
if a.kind == tySet:
|
||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||
of tySet:
|
||||
if a.kind == tySet:
|
||||
if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
|
||||
result = isSubtype
|
||||
else:
|
||||
else:
|
||||
result = typeRel(c, f.sons[0], a.sons[0])
|
||||
if result <= isConvertible:
|
||||
if result <= isConvertible:
|
||||
result = isNone # BUGFIX!
|
||||
of tyPtr, tyRef:
|
||||
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
|
||||
of tyCString: result = isConvertible
|
||||
else: discard
|
||||
of tyString:
|
||||
of tyString:
|
||||
case a.kind
|
||||
of tyString:
|
||||
of tyString:
|
||||
if tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||
result = isNilConversion
|
||||
else:
|
||||
|
|
@ -848,7 +873,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyArray:
|
||||
if (firstOrd(a.sons[0]) == 0) and
|
||||
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
|
||||
(a.sons[1].kind == tyChar):
|
||||
(a.sons[1].kind == tyChar):
|
||||
result = isConvertible
|
||||
else: discard
|
||||
|
||||
|
|
@ -863,9 +888,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
let ff = rootf.sons[i]
|
||||
let aa = roota.sons[i]
|
||||
result = typeRel(c, ff, aa)
|
||||
if result == isNone: return
|
||||
if result == isNone: return
|
||||
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
|
||||
else:
|
||||
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")
|
||||
# simply no match for now:
|
||||
discard
|
||||
elif x.kind == tyGenericInst and
|
||||
elif x.kind == tyGenericInst and
|
||||
(f.sons[0] == x.sons[0]) and
|
||||
(sonsLen(x) - 1 == sonsLen(f)):
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
if x.sons[i].kind == tyGenericParam:
|
||||
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
|
||||
else:
|
||||
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}:
|
||||
internalError("wrong instantiated type!")
|
||||
put(c.bindings, f.sons[i], x)
|
||||
|
||||
|
||||
of tyAnd:
|
||||
considerPreviousT:
|
||||
for branch in f.sons:
|
||||
if typeRel(c, branch, aOrig) < isSubtype:
|
||||
return isNone
|
||||
|
||||
bindingRet isGeneric
|
||||
let x = typeRel(c, branch, aOrig)
|
||||
if x < isSubtype: return isNone
|
||||
# 'and' implies minimum matching result:
|
||||
if x < result: result = x
|
||||
bindingRet result
|
||||
|
||||
of tyOr:
|
||||
considerPreviousT:
|
||||
result = isNone
|
||||
for branch in f.sons:
|
||||
if typeRel(c, branch, aOrig) >= isSubtype:
|
||||
bindingRet isGeneric
|
||||
|
||||
return isNone
|
||||
let x = typeRel(c, branch, aOrig)
|
||||
# 'or' implies maximum matching result:
|
||||
if x > result: result = x
|
||||
if result >= isSubtype:
|
||||
bindingRet result
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
of tyNot:
|
||||
considerPreviousT:
|
||||
for branch in f.sons:
|
||||
if typeRel(c, branch, aOrig) != isNone:
|
||||
return isNone
|
||||
|
||||
|
||||
bindingRet isGeneric
|
||||
|
||||
of tyAnything:
|
||||
|
|
@ -961,7 +991,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
if x == nil:
|
||||
if c.callee.kind == tyGenericBody and
|
||||
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
|
||||
# any value" and what we need is "match any type", which can be encoded
|
||||
# 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
|
||||
c.typedescMatched = true
|
||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||
if result > isGeneric: result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
|
|
@ -998,13 +1029,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
return isNone
|
||||
if doBind:
|
||||
put(c.bindings, f, concrete)
|
||||
elif result > isGeneric:
|
||||
result = isGeneric
|
||||
elif a.kind == tyEmpty:
|
||||
result = isGeneric
|
||||
elif x.kind == tyGenericParam:
|
||||
result = isGeneric
|
||||
else:
|
||||
result = typeRel(c, x, a) # check if it fits
|
||||
|
||||
if result > isGeneric: result = isGeneric
|
||||
|
||||
of tyStatic:
|
||||
let prev = PType(idTableGet(c.bindings, f))
|
||||
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
|
||||
# type, so we should not perform this check earlier
|
||||
if a.kind != tyTypeDesc: return isNone
|
||||
|
||||
|
||||
if f.base.kind == tyNone:
|
||||
result = isGeneric
|
||||
else:
|
||||
result = typeRel(c, f.base, a.base)
|
||||
|
||||
|
||||
if result != isNone:
|
||||
put(c.bindings, f, a)
|
||||
else:
|
||||
|
|
@ -1049,9 +1083,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
result = typeRel(c, prev.base, a.base)
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
|
||||
of tyIter:
|
||||
if a.kind == tyIter or
|
||||
if a.kind == tyIter or
|
||||
(a.kind == tyProc and tfIterator in a.flags):
|
||||
result = typeRel(c, f.base, a.base)
|
||||
else:
|
||||
|
|
@ -1059,7 +1093,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
|
||||
of tyStmt:
|
||||
result = isGeneric
|
||||
|
||||
|
||||
of tyProxy:
|
||||
result = isEqual
|
||||
|
||||
|
|
@ -1078,11 +1112,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
else:
|
||||
localError(f.n.info, errTypeExpected)
|
||||
result = isNone
|
||||
|
||||
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||
|
||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, f)
|
||||
result = typeRel(m, f, a)
|
||||
|
|
@ -1095,9 +1129,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
|
|||
if result == nil:
|
||||
internalError(arg.info, "getInstantiatedType")
|
||||
result = errorType(c)
|
||||
|
||||
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||
c: PContext): PNode =
|
||||
|
||||
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||
c: PContext): PNode =
|
||||
result = newNodeI(kind, arg.info)
|
||||
if containsGenericType(f):
|
||||
if not m.hasFauxMatch:
|
||||
|
|
@ -1110,10 +1144,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
|||
addSon(result, ast.emptyNode)
|
||||
addSon(result, arg)
|
||||
|
||||
proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg: PNode): PNode =
|
||||
proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg: PNode): PNode =
|
||||
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 dest = c.converters[i].typ.sons[0]
|
||||
# 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:
|
||||
let srca = typeRel(m, src, a)
|
||||
if srca notin {isEqual, isGeneric}: continue
|
||||
|
||||
|
||||
let destIsGeneric = containsGenericType(dest)
|
||||
if destIsGeneric:
|
||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||
let fdest = typeRel(m, f, dest)
|
||||
if fdest in {isEqual, isGeneric}:
|
||||
if fdest in {isEqual, isGeneric}:
|
||||
markUsed(arg.info, c.converters[i])
|
||||
var s = newSymNode(c.converters[i])
|
||||
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
|
||||
return result
|
||||
|
||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg: PNode): PNode =
|
||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
arg: PNode): PNode =
|
||||
# arg.typ can be nil in 'suggest':
|
||||
if isNil(arg.typ): return nil
|
||||
|
||||
|
|
@ -1181,12 +1215,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
arg = argSemantized
|
||||
argType = argType
|
||||
c = m.c
|
||||
|
||||
|
||||
if tfHasStatic in fMaybeStatic.flags:
|
||||
# XXX: When implicit statics are the default
|
||||
# this will be done earlier - we just have to
|
||||
# make sure that static types enter here
|
||||
|
||||
|
||||
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder
|
||||
# and finally start using tyTypedesc for generic types properly.
|
||||
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.n = evaluated
|
||||
argType = arg.typ
|
||||
|
||||
|
||||
var
|
||||
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
|
||||
else: argType
|
||||
|
||||
|
||||
r = typeRel(m, f, a)
|
||||
|
||||
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 isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||
of isGeneric, isInferred: inc(m.genericMatches)
|
||||
of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
|
||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||
of isInferredConvertible:
|
||||
inc(m.convMatches)
|
||||
of isEqual: inc(m.exactMatches)
|
||||
of isNone: discard
|
||||
|
||||
|
|
@ -1232,7 +1267,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
elif f.kind == tyStatic:
|
||||
return arg.typ.n
|
||||
else:
|
||||
return argOrig
|
||||
return argSemantized # argOrig
|
||||
|
||||
if r != isNone and f.isInlineIterator:
|
||||
var inlined = newTypeS(tyStatic, c)
|
||||
|
|
@ -1244,21 +1279,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
case r
|
||||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isIntConv:
|
||||
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isSubtype:
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
of isSubrange:
|
||||
inc(m.subtypeMatches)
|
||||
#result = copyTree(arg)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
if f.kind == tyVar:
|
||||
result = arg
|
||||
else:
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isInferred, isInferredConvertible:
|
||||
inc(m.genericMatches)
|
||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||
result = c.semInferredLambda(c, m.bindings, arg)
|
||||
else:
|
||||
|
|
@ -1267,42 +1303,36 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
if r == isInferredConvertible:
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||
else:
|
||||
inc(m.genericMatches)
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
when true:
|
||||
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
elif arg.typ != nil and arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
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)
|
||||
if arg.typ == nil:
|
||||
result = arg
|
||||
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
elif arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
else:
|
||||
result = arg
|
||||
of isFromIntLit:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches, 256)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isEqual:
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isEqual:
|
||||
inc(m.exactMatches)
|
||||
result = copyTree(arg)
|
||||
result = arg
|
||||
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:
|
||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||
if a.kind in {tyProxy, tyUnknown}:
|
||||
inc(m.genericMatches)
|
||||
m.fauxMatch = a.kind
|
||||
return copyTree(arg)
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
return arg
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
# check for a base type match, which supports varargs[T] without []
|
||||
# constructor in a call:
|
||||
if result == nil and f.kind == tyVarargs:
|
||||
|
|
@ -1323,7 +1353,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
arg, argOrig: PNode): PNode =
|
||||
if arg == nil or arg.kind notin nkSymChoices:
|
||||
result = paramTypesMatchAux(m, f, a, arg, argOrig)
|
||||
else:
|
||||
else:
|
||||
# CAUTION: The order depends on the used hashing scheme. Thus it is
|
||||
# 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
|
||||
|
|
@ -1337,28 +1367,37 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
y.calleeSym = m.calleeSym
|
||||
z.calleeSym = m.calleeSym
|
||||
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:
|
||||
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)
|
||||
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
|
||||
of csEmpty, csNoMatch:
|
||||
of csEmpty, csNoMatch:
|
||||
x = z
|
||||
best = i
|
||||
x.state = csMatch
|
||||
of csMatch:
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(x, z)
|
||||
if cmp < 0:
|
||||
best = i
|
||||
x = z
|
||||
elif cmp == 0:
|
||||
y = z # z is as good as x
|
||||
if x.state == csEmpty:
|
||||
if x.state == csEmpty:
|
||||
result = nil
|
||||
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
||||
if x.state != csMatch:
|
||||
internalError(arg.info, "x.state is not csMatch")
|
||||
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
||||
if x.state != csMatch:
|
||||
internalError(arg.info, "x.state is not csMatch")
|
||||
# ambiguous: more than one symbol fits!
|
||||
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
||||
# anyway:
|
||||
|
|
@ -1371,7 +1410,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
||||
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)
|
||||
father.sons[at] = son
|
||||
|
||||
|
|
@ -1415,7 +1454,7 @@ proc incrIndexType(t: PType) =
|
|||
inc t.sons[0].n.sons[1].intVal
|
||||
|
||||
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.} =
|
||||
if not formal.constraint.isNil:
|
||||
if matchNodeKinds(formal.constraint, n):
|
||||
|
|
@ -1445,20 +1484,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
# named param
|
||||
# check if m.callee has such a param:
|
||||
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)
|
||||
m.state = csNoMatch
|
||||
return
|
||||
return
|
||||
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
|
||||
if formal == nil:
|
||||
if formal == nil:
|
||||
# no error message!
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if containsOrIncl(marker, formal.position):
|
||||
return
|
||||
if containsOrIncl(marker, formal.position):
|
||||
# already in namedParams:
|
||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
return
|
||||
return
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
||||
n.sons[a].typ = n.sons[a].sons[1].typ
|
||||
|
|
@ -1468,7 +1507,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
m.state = csNoMatch
|
||||
return
|
||||
checkConstraint(n.sons[a].sons[1])
|
||||
if m.baseTypeMatch:
|
||||
if m.baseTypeMatch:
|
||||
#assert(container == nil)
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
addSon(container, arg)
|
||||
|
|
@ -1505,7 +1544,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
m.state = csNoMatch
|
||||
return
|
||||
else:
|
||||
if m.callee.n.sons[f].kind != nkSym:
|
||||
if m.callee.n.sons[f].kind != nkSym:
|
||||
internalError(n.sons[a].info, "matches")
|
||||
return
|
||||
formal = m.callee.n.sons[f].sym
|
||||
|
|
@ -1513,7 +1552,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
# already in namedParams:
|
||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
return
|
||||
return
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
|
|
@ -1526,7 +1565,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
|||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
addSon(container, arg)
|
||||
setSon(m.call, formal.position + 1,
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
#if f != formalLen - 1: container = nil
|
||||
|
||||
|
|
@ -1601,7 +1640,7 @@ when not declared(tests):
|
|||
|
||||
tests:
|
||||
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||
|
||||
|
||||
proc `|` (t1, t2: PType): PType =
|
||||
result = newType(tyOr, dummyOwner)
|
||||
result.rawAddSon(t1)
|
||||
|
|
@ -1622,12 +1661,12 @@ tests:
|
|||
|
||||
proc array(x: int, t: PType): PType =
|
||||
result = newType(tyArray, dummyOwner)
|
||||
|
||||
|
||||
var n = newNodeI(nkRange, UnknownLineInfo())
|
||||
addSon(n, newIntNode(nkIntLit, 0))
|
||||
addSon(n, newIntNode(nkIntLit, x))
|
||||
let range = newType(tyRange, dummyOwner)
|
||||
|
||||
|
||||
result.rawAddSon(range)
|
||||
result.rawAddSon(t)
|
||||
|
||||
|
|
@ -1653,7 +1692,7 @@ tests:
|
|||
|
||||
setup:
|
||||
var c: TCandidate
|
||||
InitCandidate(nil, c, nil)
|
||||
initCandidate(nil, c, nil)
|
||||
|
||||
template yes(x, y) =
|
||||
test astToStr(x) & " is " & astToStr(y):
|
||||
|
|
@ -1662,7 +1701,7 @@ tests:
|
|||
template no(x, y) =
|
||||
test astToStr(x) & " is not " & astToStr(y):
|
||||
check typeRel(c, y, x) == isNone
|
||||
|
||||
|
||||
yes seq(any), array(10, int) | seq(any)
|
||||
# Sure, seq[any] is directly included
|
||||
|
||||
|
|
@ -1670,16 +1709,16 @@ tests:
|
|||
yes seq(int), seq(number)
|
||||
# Sure, the int sequence is certainly
|
||||
# part of the number sequences (and all sequences)
|
||||
|
||||
|
||||
no seq(any), seq(float)
|
||||
# Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
|
||||
|
||||
yes seq(int|string), seq(any)
|
||||
# Sure
|
||||
|
||||
|
||||
yes seq(int&string), seq(any)
|
||||
# Again
|
||||
|
||||
|
||||
yes seq(int&string), seq(int)
|
||||
# A bit more complicated
|
||||
# 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)
|
||||
# Nope, seq[string] is not included in not included in
|
||||
# the seq[int|float] set
|
||||
|
||||
|
||||
no seq(!(int|string)), seq(string)
|
||||
# A sequence that is neither seq[int] or seq[string]
|
||||
# is obviously not seq[string]
|
||||
|
||||
|
||||
no seq(!int), seq(number)
|
||||
# Now your head should start to hurt a bit
|
||||
# A sequence that is not seq[int] is not necessarily a number sequence
|
||||
# it could well be seq[string] for example
|
||||
|
||||
|
||||
yes seq(!(int|string)), seq(!string)
|
||||
# all sequnece types besides seq[int] and seq[string]
|
||||
# are subset of all sequence types that are not seq[string]
|
||||
|
||||
no seq(!(int|string)), seq(!(string|TFoo))
|
||||
# Nope, seq[TFoo] is included in the first set, but not in the second
|
||||
|
||||
|
||||
no seq(!string), seq(!number)
|
||||
# Nope, seq[int] in included in the first set, but not in the second
|
||||
|
||||
|
|
@ -1712,7 +1751,7 @@ tests:
|
|||
yes seq(!int), seq(any)
|
||||
no seq(any), seq(!any)
|
||||
no seq(!int), seq(!any)
|
||||
|
||||
|
||||
yes int, ordinal
|
||||
no string, ordinal
|
||||
|
||||
|
|
|
|||
|
|
@ -17,27 +17,27 @@
|
|||
# * introduces method dispatchers
|
||||
# * performs lambda lifting for closure support
|
||||
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
import
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||
lambdalifting, sempass2, lowerings
|
||||
|
||||
# implementation
|
||||
|
||||
type
|
||||
type
|
||||
PTransNode* = distinct PNode
|
||||
|
||||
|
||||
PTransCon = ref TTransCon
|
||||
TTransCon{.final.} = object # part of TContext; stackable
|
||||
mapping: TIdNodeTable # mapping from symbols to nodes
|
||||
owner: PSym # current owner
|
||||
forStmt: PNode # current for stmt
|
||||
forLoopBody: PTransNode # transformed for loop body
|
||||
yieldStmts: int # we count the number of yield statements,
|
||||
forLoopBody: PTransNode # transformed for loop body
|
||||
yieldStmts: int # we count the number of yield statements,
|
||||
# because we need to introduce new variables
|
||||
# if we encounter the 2nd yield statement
|
||||
next: PTransCon # for stacking
|
||||
|
||||
|
||||
TTransfContext = object of passes.TPassContext
|
||||
module: PSym
|
||||
transCon: PTransCon # top of a TransCon stack
|
||||
|
|
@ -46,52 +46,52 @@ type
|
|||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
result = PTransNode(shallowCopy(a))
|
||||
|
||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
var x = newNodeI(kind, info)
|
||||
newSeq(x.sons, sons)
|
||||
result = x.PTransNode
|
||||
|
||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||
sons: int): PTransNode {.inline.} =
|
||||
var x = newNodeIT(kind, n.info, n.typ)
|
||||
newSeq(x.sons, sons)
|
||||
x.typ = n.typ
|
||||
result = x.PTransNode
|
||||
|
||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||
var n = PNode(a)
|
||||
n.sons[i] = PNode(x)
|
||||
|
||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||
var n = PNode(a)
|
||||
result = n.sons[i].PTransNode
|
||||
|
||||
|
||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
||||
|
||||
proc newTransCon(owner: PSym): PTransCon =
|
||||
proc newTransCon(owner: PSym): PTransCon =
|
||||
assert owner != nil
|
||||
new(result)
|
||||
initIdNodeTable(result.mapping)
|
||||
result.owner = owner
|
||||
|
||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||
t.next = c.transCon
|
||||
c.transCon = t
|
||||
|
||||
proc popTransCon(c: PTransf) =
|
||||
proc popTransCon(c: PTransf) =
|
||||
if (c.transCon == nil): internalError("popTransCon")
|
||||
c.transCon = c.transCon.next
|
||||
|
||||
proc getCurrOwner(c: PTransf): PSym =
|
||||
proc getCurrOwner(c: PTransf): PSym =
|
||||
if c.transCon != nil: result = c.transCon.owner
|
||||
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.typ = skipTypes(typ, {tyGenericInst})
|
||||
incl(result.flags, sfFromGeneric)
|
||||
|
|
@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
|
|||
|
||||
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
||||
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])
|
||||
|
||||
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[0] = PTransNode(le)
|
||||
result[1] = ri
|
||||
|
|
@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
|||
# return liftIterSym(n)
|
||||
var b: PNode
|
||||
var tc = c.transCon
|
||||
if sfBorrow in n.sym.flags:
|
||||
if sfBorrow in n.sym.flags:
|
||||
# simply exchange the symbol:
|
||||
b = n.sym.getBody
|
||||
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym)
|
||||
b.info = n.info
|
||||
else:
|
||||
else:
|
||||
b = n
|
||||
while tc != nil:
|
||||
while tc != nil:
|
||||
result = idNodeTableGet(tc.mapping, b.sym)
|
||||
if result != nil: return
|
||||
tc = tc.next
|
||||
result = b
|
||||
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
result = PTransNode(transformSymAux(c, n))
|
||||
|
||||
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||
result = newTransNode(v)
|
||||
for i in countup(0, sonsLen(v)-1):
|
||||
var it = v.sons[i]
|
||||
if it.kind == nkCommentStmt:
|
||||
if it.kind == nkCommentStmt:
|
||||
result[i] = PTransNode(it)
|
||||
elif it.kind == nkIdentDefs:
|
||||
elif it.kind == nkIdentDefs:
|
||||
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
||||
internalAssert(it.len == 3)
|
||||
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[2] = transform(c, it.sons[2])
|
||||
result[i] = defs
|
||||
else:
|
||||
if it.kind != nkVarTuple:
|
||||
else:
|
||||
if it.kind != nkVarTuple:
|
||||
internalError(it.info, "transformVarSection: not nkVarTuple")
|
||||
var L = sonsLen(it)
|
||||
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)
|
||||
incl(newVar.flags, sfFromGeneric)
|
||||
newVar.owner = getCurrOwner(c)
|
||||
|
|
@ -188,12 +188,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
|||
else:
|
||||
result[i] = PTransNode(it)
|
||||
|
||||
proc hasContinue(n: PNode): bool =
|
||||
proc hasContinue(n: PNode): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
||||
of nkContinueStmt: result = true
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if hasContinue(n.sons[i]): return true
|
||||
|
||||
proc newLabel(c: PTransf, n: PNode): PSym =
|
||||
|
|
@ -224,10 +224,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
|||
discard c.breakSyms.pop
|
||||
result[0] = newSymNode(labl).PTransNode
|
||||
|
||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
# What if it contains "continue" and "break"? "break" needs
|
||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||
# What if it contains "continue" and "break"? "break" needs
|
||||
# an explicit label too, but not the same!
|
||||
|
||||
|
||||
# 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
|
||||
# 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[1] = transform(c, n)
|
||||
discard c.contSyms.pop()
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n)
|
||||
|
||||
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
||||
|
|
@ -273,27 +273,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
|||
result = transformSons(c, n)
|
||||
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?
|
||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
transform(c, newTupleAccess(n, i))))
|
||||
|
||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
# nothing to be done for leaves:
|
||||
result = PTransNode(n)
|
||||
of nkVarSection, nkLetSection:
|
||||
result = transformVarSection(c, n)
|
||||
else:
|
||||
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])
|
||||
|
||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
result = newTransNode(nkStmtList, n.info, 0)
|
||||
var e = n.sons[0]
|
||||
# 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
|
||||
c.transCon.forStmt.len != 3:
|
||||
e = skipConv(e)
|
||||
if e.kind == nkPar:
|
||||
for i in countup(0, sonsLen(e) - 1):
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
if e.kind == nkPar:
|
||||
for i in countup(0, sonsLen(e) - 1):
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
transform(c, e.sons[i])))
|
||||
else:
|
||||
else:
|
||||
unpackTuple(c, e, result)
|
||||
else:
|
||||
else:
|
||||
var x = transform(c, e)
|
||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
||||
|
||||
|
||||
inc(c.transCon.yieldStmts)
|
||||
if c.transCon.yieldStmts <= 1:
|
||||
# common case
|
||||
add(result, c.transCon.forLoopBody)
|
||||
else:
|
||||
else:
|
||||
# we need to introduce new local variables:
|
||||
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:
|
||||
# addr ( deref ( x )) --> x
|
||||
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:
|
||||
var dest = skipTypes(n.typ, abstractVarRange)
|
||||
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
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 ;-)
|
||||
if not isOrdinalType(source):
|
||||
# float -> int conversions. ugh.
|
||||
result = transformSons(c, n)
|
||||
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,
|
||||
# but no range check:
|
||||
result = transformSons(c, n)
|
||||
else:
|
||||
else:
|
||||
# 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)
|
||||
else:
|
||||
result = newTransNode(nkChckRange, n, 3)
|
||||
|
|
@ -368,7 +368,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
|||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||
of tyFloat..tyFloat128:
|
||||
# XXX int64 -> float conversion?
|
||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||
result = newTransNode(nkChckRangeF, n, 3)
|
||||
dest = skipTypes(n.typ, abstractVar)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
|
|
@ -378,81 +378,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
|||
result = transformSons(c, n)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = transform(c, n.sons[1])
|
||||
of tyCString:
|
||||
if source.kind == tyString:
|
||||
of tyCString:
|
||||
if source.kind == tyString:
|
||||
result = newTransNode(nkStringToCString, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyString:
|
||||
if source.kind == tyCString:
|
||||
of tyString:
|
||||
if source.kind == tyCString:
|
||||
result = newTransNode(nkCStringToString, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyRef, tyPtr:
|
||||
of tyRef, tyPtr:
|
||||
dest = skipTypes(dest, abstractPtrs)
|
||||
source = skipTypes(source, abstractPtrs)
|
||||
if source.kind == tyObject:
|
||||
if source.kind == tyObject:
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff < 0:
|
||||
if diff < 0:
|
||||
result = newTransNode(nkObjUpConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
elif diff > 0:
|
||||
elif diff > 0:
|
||||
result = newTransNode(nkObjDownConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyObject:
|
||||
of tyObject:
|
||||
var diff = inheritanceDiff(dest, source)
|
||||
if diff < 0:
|
||||
if diff < 0:
|
||||
result = newTransNode(nkObjUpConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
elif diff > 0:
|
||||
elif diff > 0:
|
||||
result = newTransNode(nkObjDownConv, n, 1)
|
||||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
else:
|
||||
result = transform(c, n.sons[1])
|
||||
of tyGenericParam, tyOrdinal:
|
||||
result = transform(c, n.sons[1])
|
||||
# happens sometimes for generated assignments, etc.
|
||||
else:
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
||||
type
|
||||
TPutArgInto = enum
|
||||
|
||||
type
|
||||
TPutArgInto = enum
|
||||
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
|
||||
# inline context.
|
||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
return paDirectMapping # XXX really correct?
|
||||
# what if ``arg`` has side-effects?
|
||||
case arg.kind
|
||||
of nkEmpty..nkNilLit:
|
||||
of nkEmpty..nkNilLit:
|
||||
result = paDirectMapping
|
||||
of nkPar, nkCurly, nkBracket:
|
||||
of nkPar, nkCurly, nkBracket:
|
||||
result = paFastAsgn
|
||||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||
result = paDirectMapping
|
||||
else:
|
||||
else:
|
||||
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
||||
else: result = paFastAsgn
|
||||
|
||||
|
||||
proc findWrongOwners(c: PTransf, n: PNode) =
|
||||
if n.kind == nkVarSection:
|
||||
let x = n.sons[0].sons[0]
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
# put mapping from formal parameters to actual parameters
|
||||
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
||||
|
|
@ -466,26 +466,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
result[0] = newSymNode(labl).PTransNode
|
||||
|
||||
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):
|
||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||
discard c.breakSyms.pop
|
||||
return result
|
||||
|
||||
|
||||
#echo "transforming: ", renderTree(n)
|
||||
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
||||
|
||||
|
||||
var loopBody = transformLoopBody(c, n.sons[length-1])
|
||||
|
||||
result[1] = stmtList
|
||||
discard c.breakSyms.pop
|
||||
|
||||
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
|
||||
add(stmtList, v.PTransNode)
|
||||
|
||||
|
||||
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
||||
# iterator!
|
||||
let iter = call.sons[0].sym
|
||||
|
|
@ -496,9 +496,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
if iter.kind != skIterator: return result
|
||||
# generate access statements for the parameters (unless they are constant)
|
||||
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 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
|
||||
case putArgInto(arg, formal.typ)
|
||||
of paDirectMapping:
|
||||
|
|
@ -527,20 +527,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
|||
popInfoContext()
|
||||
popTransCon(c)
|
||||
# echo "transformed: ", stmtList.PNode.renderTree
|
||||
|
||||
proc getMagicOp(call: PNode): TMagic =
|
||||
|
||||
proc getMagicOp(call: PNode): TMagic =
|
||||
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
|
||||
else:
|
||||
result = mNone
|
||||
|
||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||
# removes `elif` branches of a case stmt
|
||||
# adds ``else: nil`` if needed for the code generator
|
||||
result = newTransNode(nkCaseStmt, n, 0)
|
||||
var ifs = PTransNode(nil)
|
||||
for i in 0 .. sonsLen(n)-1:
|
||||
for i in 0 .. sonsLen(n)-1:
|
||||
var it = n.sons[i]
|
||||
var e = transform(c, it)
|
||||
case it.kind
|
||||
|
|
@ -564,8 +564,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
|
|||
var elseBranch = newTransNode(nkElse, n.info, 1)
|
||||
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
||||
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
|
||||
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
||||
result = n.PTransNode
|
||||
|
|
@ -573,45 +573,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
|||
result = newTransNode(n)
|
||||
for i in 0 .. < n.len:
|
||||
result[i] = transform(c, skipConv(n.sons[i]))
|
||||
|
||||
proc getMergeOp(n: PNode): PSym =
|
||||
|
||||
proc getMergeOp(n: PNode): PSym =
|
||||
case n.kind
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
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
|
||||
else: discard
|
||||
|
||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||
let op2 = getMergeOp(a)
|
||||
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)
|
||||
else:
|
||||
else:
|
||||
addSon(d, copyTree(a))
|
||||
|
||||
proc flattenTree(root: PNode): PNode =
|
||||
|
||||
proc flattenTree(root: PNode): PNode =
|
||||
let op = getMergeOp(root)
|
||||
if op != nil:
|
||||
if op != nil:
|
||||
result = copyNode(root)
|
||||
addSon(result, copyTree(root.sons[0]))
|
||||
flattenTreeAux(result, root, op)
|
||||
else:
|
||||
else:
|
||||
result = root
|
||||
|
||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
var n = flattenTree(n)
|
||||
let op = getMergeOp(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)
|
||||
add(result, transform(c, n.sons[0]))
|
||||
var j = 1
|
||||
while j < sonsLen(n):
|
||||
while j < sonsLen(n):
|
||||
var a = transform(c, n.sons[j]).PNode
|
||||
inc(j)
|
||||
if isConstExpr(a):
|
||||
if isConstExpr(a):
|
||||
while (j < sonsLen(n)):
|
||||
let b = transform(c, n.sons[j]).PNode
|
||||
if not isConstExpr(b): break
|
||||
|
|
@ -640,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
|||
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||
# symbols that expand to a complex constant (array, etc.) should not be
|
||||
# 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
|
||||
|
||||
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||
|
|
@ -673,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
|||
else:
|
||||
result = n
|
||||
|
||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
# nothing to be done for leaves:
|
||||
result = PTransNode(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))
|
||||
if n.kind == nkMethodDef: methodDef(s, false)
|
||||
result = PTransNode(n)
|
||||
of nkForStmt:
|
||||
of nkForStmt:
|
||||
result = transformFor(c, n)
|
||||
of nkParForStmt:
|
||||
result = transformSons(c, n)
|
||||
|
|
@ -713,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
add(result, PTransNode(newSymNode(labl)))
|
||||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkWhileStmt: result = transformWhile(c, n)
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||
nkCallStrLit:
|
||||
result = transformCall(c, n)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
of nkAddr, nkHiddenAddr:
|
||||
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
of nkDerefExpr, nkHiddenDeref:
|
||||
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
result = transformConv(c, n)
|
||||
of nkDiscardStmt:
|
||||
result = PTransNode(n)
|
||||
|
|
@ -730,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
# ensure that e.g. discard "some comment" gets optimized away
|
||||
# completely:
|
||||
result = PTransNode(newNode(nkCommentStmt))
|
||||
of nkCommentStmt, nkTemplateDef:
|
||||
of nkCommentStmt, nkTemplateDef:
|
||||
return n.PTransNode
|
||||
of nkConstSection:
|
||||
# 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)
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of nkYieldStmt:
|
||||
of nkYieldStmt:
|
||||
if c.inlining > 0:
|
||||
result = transformYield(c, n)
|
||||
else:
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of nkBlockStmt, nkBlockExpr:
|
||||
result = transformBlock(c, n)
|
||||
|
|
@ -764,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
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
|
||||
# this step! We have to rely that the semantic pass transforms too errornous
|
||||
# nodes into an empty node.
|
||||
|
|
@ -774,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
|||
popTransCon(c)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
new(result)
|
||||
result.contSyms = @[]
|
||||
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
|
||||
result.add(',' & typeStr)
|
||||
of nkTupleTy:
|
||||
assert len(n) > 0
|
||||
result = "tuple["
|
||||
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
||||
result[<len(result)] = ']'
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
|
|||
|
||||
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] =
|
||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||
var f = tos
|
||||
|
|
@ -257,7 +257,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
|
|||
let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
|
||||
abstractPtrs)
|
||||
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:
|
||||
c.currentExceptionB = c.currentExceptionA
|
||||
c.currentExceptionA = nil
|
||||
|
|
@ -349,14 +349,14 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
|
|||
if dest.kind != rkFloat:
|
||||
myreset(dest); dest.kind = rkFloat
|
||||
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)
|
||||
else:
|
||||
dest.floatVal = src.floatVal
|
||||
else:
|
||||
asgnComplex(dest, src)
|
||||
|
||||
proc compile(c: PCtx, s: PSym): int =
|
||||
proc compile(c: PCtx, s: PSym): int =
|
||||
result = vmgen.genProc(c, s)
|
||||
when debugEchoCode: c.echoCode result
|
||||
#c.echoCode
|
||||
|
|
@ -396,10 +396,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
pc = tos.comesFrom
|
||||
tos = tos.next
|
||||
let retVal = regs[0]
|
||||
if tos.isNil:
|
||||
if tos.isNil:
|
||||
#echo "RET ", retVal.rendertree
|
||||
return retVal
|
||||
|
||||
|
||||
move(regs, tos.slots)
|
||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||
if c.code[pc].opcode == opcIndCallAsgn:
|
||||
|
|
@ -653,7 +653,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcSubu:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
|
||||
of opcMulu:
|
||||
of opcMulu:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
|
||||
of opcDivu:
|
||||
|
|
@ -726,7 +726,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcLeSet:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
|
||||
of opcEqSet:
|
||||
of opcEqSet:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
|
||||
of opcLtSet:
|
||||
|
|
@ -737,9 +737,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcMulSet:
|
||||
decodeBC(rkNode)
|
||||
createSet(regs[ra])
|
||||
move(regs[ra].node.sons,
|
||||
move(regs[ra].node.sons,
|
||||
nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
|
||||
of opcPlusSet:
|
||||
of opcPlusSet:
|
||||
decodeBC(rkNode)
|
||||
createSet(regs[ra])
|
||||
move(regs[ra].node.sons,
|
||||
|
|
@ -753,7 +753,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
decodeBC(rkNode)
|
||||
createSet(regs[ra])
|
||||
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:
|
||||
decodeBC(rkNode)
|
||||
createStr regs[ra]
|
||||
|
|
@ -793,7 +793,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
assert c.code[pc].opcode == opcSubStr
|
||||
let rd = c.code[pc].regA
|
||||
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)
|
||||
of opcParseFloat:
|
||||
decodeBC(rkInt)
|
||||
|
|
@ -896,12 +896,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
# we know the next instruction is a 'fjmp':
|
||||
let branch = c.constants[instr.regBx-wordExcess]
|
||||
var cond = false
|
||||
for j in countup(0, sonsLen(branch) - 2):
|
||||
if overlap(regs[ra].regToNode, branch.sons[j]):
|
||||
for j in countup(0, sonsLen(branch) - 2):
|
||||
if overlap(regs[ra].regToNode, branch.sons[j]):
|
||||
cond = true
|
||||
break
|
||||
assert c.code[pc+1].opcode == opcFJmp
|
||||
inc pc
|
||||
inc pc
|
||||
# we skip this instruction so that the final 'inc(pc)' skips
|
||||
# the following jump
|
||||
if not cond:
|
||||
|
|
@ -1273,7 +1273,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcNSetIntVal:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind in {nkCharLit..nkInt64Lit} and
|
||||
if dest.kind in {nkCharLit..nkInt64Lit} and
|
||||
regs[rb].kind in {rkInt}:
|
||||
dest.intVal = regs[rb].intVal
|
||||
else:
|
||||
|
|
@ -1281,24 +1281,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcNSetFloatVal:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind in {nkFloatLit..nkFloat64Lit} and
|
||||
if dest.kind in {nkFloatLit..nkFloat64Lit} and
|
||||
regs[rb].kind in {rkFloat}:
|
||||
dest.floatVal = regs[rb].floatVal
|
||||
else:
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
|
||||
of opcNSetSymbol:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
|
||||
dest.sym = regs[rb].node.sym
|
||||
else:
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
|
||||
of opcNSetIdent:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
|
||||
dest.ident = regs[rb].node.ident
|
||||
else:
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||
of opcNSetType:
|
||||
decodeB(rkNode)
|
||||
|
|
@ -1309,7 +1309,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
|||
of opcNSetStrVal:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
||||
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
||||
regs[rb].kind in {rkNode}:
|
||||
dest.strVal = regs[rb].node.strVal
|
||||
else:
|
||||
|
|
@ -1435,8 +1435,9 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
|||
newSeq(tos.slots, c.prc.maxSlots)
|
||||
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
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)
|
||||
|
||||
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:
|
||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
if result.info.line < 0: result.info = n.info
|
||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ path="$lib/pure/unidecode"
|
|||
gcc.options.always = "-w"
|
||||
gcc.cpp.options.always = "-w -fpermissive"
|
||||
@else:
|
||||
gcc.options.always = "-w"
|
||||
gcc.options.always = "-w"
|
||||
gcc.cpp.options.always = "-w -fpermissive"
|
||||
@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.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||
vcc.options.always = "/nologo"
|
||||
vcc.options.speed = "/Ox /arch:SSE2"
|
||||
vcc.options.speed = "/O2 /arch:SSE2"
|
||||
vcc.options.size = "/O1"
|
||||
|
||||
# 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
|
||||
using Posix's inotify API.
|
||||
|
||||
* `asyncfile <asyncfile.html>`_
|
||||
This module implements asynchronous file reading and writing using
|
||||
``asyncdispatch``.
|
||||
|
||||
Math libraries
|
||||
--------------
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ dispatch.
|
|||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Expression = object ## abstract base class for an expression
|
||||
Expression = object of RootObj ## abstract base class for an expression
|
||||
Literal = object of Expression
|
||||
x: int
|
||||
PlusExpr = object of Expression
|
||||
|
|
@ -387,7 +387,7 @@ dispatching:
|
|||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Thing = object
|
||||
Thing = object of RootObj
|
||||
Unit = object of Thing
|
||||
x: int
|
||||
|
||||
|
|
|
|||
2
koch.nim
2
koch.nim
|
|
@ -347,7 +347,7 @@ proc temp(args: string) =
|
|||
if args.len > 0: exec(finalDest & " " & args)
|
||||
|
||||
proc showHelp() =
|
||||
quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)),
|
||||
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||
CompileDate, CompileTime], QuitSuccess)
|
||||
|
||||
var op = initOptParser()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ type
|
|||
nnkStmtListType, nnkBlockType,
|
||||
nnkWith, nnkWithout,
|
||||
nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
|
||||
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||
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,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## 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.} =
|
||||
## 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,
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
|
||||
from strutils import cmpIgnoreStyle, format
|
||||
|
||||
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()];
|
||||
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
||||
|
|
@ -654,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
|
|||
|
||||
|
||||
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.} =
|
||||
case someProc.kind:
|
||||
|
|
@ -776,6 +774,22 @@ proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
|||
## An alias for 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
|
||||
## Check if two idents are identical.
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ type
|
|||
ppointer = ptr pointer
|
||||
pbyteArray = ptr array[0.. 0xffff, int8]
|
||||
|
||||
TGenSeq = object
|
||||
TGenericSeq {.importc.} = object
|
||||
len, space: int
|
||||
PGenSeq = ptr TGenSeq
|
||||
PGenSeq = ptr TGenericSeq
|
||||
|
||||
const
|
||||
GenericSeqSize = (2 * sizeof(int))
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@
|
|||
#
|
||||
|
||||
## 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``
|
||||
## is used. This suffices because Windows' console already provides the
|
||||
## is used. This suffices because Windows' console already provides the
|
||||
## wanted functionality.
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
when defined(Windows):
|
||||
proc readLineFromStdin*(prompt: string): TaintedString {.
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Reads a line from stdin.
|
||||
stdout.write(prompt)
|
||||
result = readLine(stdin)
|
||||
|
|
@ -33,27 +33,71 @@ when defined(Windows):
|
|||
stdout.write(prompt)
|
||||
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):
|
||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Reads a `password` from stdin without printing it. `password` must not
|
||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||
## ``true`` otherwise.
|
||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
|
||||
password.setLen(0)
|
||||
var c: char
|
||||
stdout.write(prompt)
|
||||
while true:
|
||||
c = getch().char
|
||||
case c
|
||||
let c = getch()
|
||||
case c.char
|
||||
of '\r', chr(0xA):
|
||||
break
|
||||
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:
|
||||
password.add(c)
|
||||
password.add(toUTF8(c.Rune))
|
||||
stdout.write "\n"
|
||||
# TODO: How to detect EOF on Windows?
|
||||
|
||||
else:
|
||||
import readline, history, termios, unsigned
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
|
|||
offset: cint
|
||||
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
||||
if result == nil:
|
||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
|
||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
|
||||
|
||||
proc finalizeRegEx(x: Regex) =
|
||||
# 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:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
|
||||
## "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
|
|
@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
|||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||
##
|
||||
## .. 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:
|
||||
##
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ __clang__
|
|||
#endif
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||
# define NIM_THREADVAR __declspec(thread)
|
||||
# define NIM_THREADVAR __declspec(thread)
|
||||
#else
|
||||
# define NIM_THREADVAR __thread
|
||||
#endif
|
||||
|
|
@ -103,7 +103,11 @@ __clang__
|
|||
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *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)
|
||||
#else
|
||||
# define N_CDECL(rettype, name) rettype name
|
||||
|
|
@ -118,7 +122,11 @@ __clang__
|
|||
# define N_FASTCALL_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
|
||||
#endif
|
||||
|
||||
|
|
@ -345,7 +353,7 @@ struct TFrame {
|
|||
#define nimln(n, file) \
|
||||
F.line = n; F.filename = file;
|
||||
|
||||
#define NIM_POSIX_INIT __attribute__((constructor))
|
||||
#define NIM_POSIX_INIT __attribute__((constructor))
|
||||
|
||||
#if defined(_MSCVER) && defined(__i386__)
|
||||
__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
|
||||
|
||||
/* 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" */
|
||||
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
||||
#endif
|
||||
|
|
@ -398,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
|
|||
# include <sys/types.h>
|
||||
# include <types/vxWind.h>
|
||||
# include <tool/gnu/toolMacros.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
|
|||
tok.line = L.line
|
||||
L.col = tok.ival
|
||||
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) =
|
||||
tok.symbol = ""
|
||||
|
|
@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
|
|||
break
|
||||
else:
|
||||
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)
|
||||
else:
|
||||
add(n.text, p.tok[p.idx].symbol)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
const
|
||||
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
||||
if n == nil: return
|
||||
var ind = repeatChar(d.indent)
|
||||
var ind = spaces(d.indent)
|
||||
case n.kind
|
||||
of rnInner:
|
||||
renderRstSons(d, n, result)
|
||||
|
|
@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add repeatChar(headlineLen, lvlToChar[n.level])
|
||||
result.add repeat(lvlToChar[n.level], headlineLen)
|
||||
of rnOverline:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
|
|
@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
var 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("\n")
|
||||
result.add(headline)
|
||||
|
|
@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
of rnTransition:
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
result.add repeatChar(78-d.indent, '-')
|
||||
result.add repeat('-', 78-d.indent)
|
||||
result.add("\n\n")
|
||||
of rnParagraph:
|
||||
result.add("\n\n")
|
||||
|
|
@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
result.add ':'
|
||||
result.add tmp
|
||||
result.add ':'
|
||||
result.add repeatChar(L - tmp.len - 2)
|
||||
result.add spaces(L - tmp.len - 2)
|
||||
renderRstToRst(d, n.sons[1], result)
|
||||
|
||||
dec(d.indent, L)
|
||||
|
|
|
|||
|
|
@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
|
|||
if level == newLevel:
|
||||
return
|
||||
if newLevel > level:
|
||||
result = repeatStr(newLevel - level, "<ul>")
|
||||
result = repeat("<ul>", newLevel - level)
|
||||
else:
|
||||
result = repeatStr(level - newLevel, "</ul>")
|
||||
result = repeat("</ul>", level - newLevel)
|
||||
level = newLevel
|
||||
|
||||
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.
|
||||
assert n.level >= 0
|
||||
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) =
|
||||
if d.meta[metaTitle].len == 0:
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@
|
|||
|
||||
type
|
||||
SortOrder* = enum ## sort order
|
||||
Descending, Ascending
|
||||
Descending, Ascending
|
||||
|
||||
{.deprecated: [TSortOrder: SortOrder].}
|
||||
|
||||
|
||||
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||
## flips `x` if ``order == Descending``;
|
||||
## 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*.
|
||||
var y = order.ord - 1
|
||||
result = (x xor y) - y
|
||||
|
|
@ -73,14 +73,15 @@ const
|
|||
onlySafeCode = true
|
||||
|
||||
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
|
||||
## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
|
||||
## the sequence will still be sorted
|
||||
## words if you have a sorted sequence and you call
|
||||
## 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::
|
||||
##
|
||||
## 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
|
||||
|
||||
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) =
|
||||
template `<-` (a, b: expr) =
|
||||
template `<-` (a, b: expr) =
|
||||
when false:
|
||||
a = b
|
||||
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],
|
||||
cmp: proc (x, y: T): int {.closure.},
|
||||
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 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
|
||||
## sensible default argument for ``cmp``, so you have to provide one
|
||||
## 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)
|
||||
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]] =
|
||||
## produces the Cartesian product of the array. Warning: complexity
|
||||
## may explode.
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export Port, SocketFlag
|
|||
##
|
||||
## Limitations/Bugs
|
||||
## ----------------
|
||||
##
|
||||
##
|
||||
## * ``except`` statement (without `try`) does not work inside async procedures.
|
||||
## * The effect system (``raises: []``) does not work with async procedures.
|
||||
## * Can't await in a ``except`` body
|
||||
|
|
@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc):
|
|||
if p.handles.len == 0 and p.timers.len == 0:
|
||||
raise newException(ValueError,
|
||||
"No handles or timers registered in dispatcher.")
|
||||
|
||||
|
||||
let llTimeout =
|
||||
if timeout == -1: winlean.INFINITE
|
||||
else: timeout.int32
|
||||
|
|
@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
|
|||
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
|
||||
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
|
||||
let fun =
|
||||
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
|
||||
|
||||
|
|
@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
|
|||
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
|
||||
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
|
||||
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
|
||||
|
||||
|
||||
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
|
||||
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
|
||||
RemoteSockaddr, RemoteSockaddrLength)
|
||||
|
|
@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc):
|
|||
else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||
)
|
||||
|
||||
|
||||
var ret = connectEx(socket.SocketHandle, it.ai_addr,
|
||||
sizeof(Sockaddr_in).cint, nil, 0, nil,
|
||||
cast[POVERLAPPED](ol))
|
||||
|
|
@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
|
|||
var dataBuf: TWSABuf
|
||||
dataBuf.buf = cast[cstring](alloc0(size))
|
||||
dataBuf.len = size
|
||||
|
||||
|
||||
var bytesReceived: Dword
|
||||
var flagsio = flags.toOSFlags().Dword
|
||||
var ol = PCustomOverlapped()
|
||||
|
|
@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc):
|
|||
# the empty string (which signals a disconnection) when there is
|
||||
# nothing left to read.
|
||||
retFuture.complete("")
|
||||
# TODO: "For message-oriented sockets, where a zero byte message is often
|
||||
# allowable, a failure with an error code of WSAEDISCON is used to
|
||||
# indicate graceful closure."
|
||||
# TODO: "For message-oriented sockets, where a zero byte message is often
|
||||
# allowable, a failure with an error code of WSAEDISCON is used to
|
||||
# indicate graceful closure."
|
||||
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
|
||||
else:
|
||||
# Request to read completed immediately.
|
||||
|
|
@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc):
|
|||
|
||||
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
|
||||
let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
|
||||
dwReceiveDataLength,
|
||||
dwReceiveDataLength,
|
||||
dwLocalAddressLength,
|
||||
dwRemoteAddressLength,
|
||||
addr dwBytesReceived, cast[POVERLAPPED](ol))
|
||||
|
|
@ -803,7 +803,7 @@ else:
|
|||
else:
|
||||
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
||||
MSG_NOSIGNAL
|
||||
|
||||
|
||||
type
|
||||
TAsyncFD* = distinct cint
|
||||
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
|
||||
|
|
@ -849,7 +849,7 @@ else:
|
|||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
register(result)
|
||||
|
||||
|
||||
proc closeSocket*(sock: TAsyncFD) =
|
||||
let disp = getGlobalDispatcher()
|
||||
sock.SocketHandle.close()
|
||||
|
|
@ -864,14 +864,14 @@ else:
|
|||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
|
||||
|
||||
|
||||
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
|
||||
let p = getGlobalDispatcher()
|
||||
if fd.SocketHandle notin p.selector:
|
||||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
|
||||
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
let p = getGlobalDispatcher()
|
||||
for info in p.selector.select(timeout):
|
||||
|
|
@ -892,7 +892,7 @@ else:
|
|||
if not cb(data.fd):
|
||||
# Callback wants to be called again.
|
||||
data.readCBs.add(cb)
|
||||
|
||||
|
||||
if EvWrite in info.events:
|
||||
let currentCBs = data.writeCBs
|
||||
data.writeCBs = @[]
|
||||
|
|
@ -900,7 +900,7 @@ else:
|
|||
if not cb(data.fd):
|
||||
# Callback wants to be called again.
|
||||
data.writeCBs.add(cb)
|
||||
|
||||
|
||||
if info.key in p.selector:
|
||||
var newEvents: set[Event]
|
||||
if data.readCBs.len != 0: newEvents = {EvRead}
|
||||
|
|
@ -913,16 +913,16 @@ else:
|
|||
discard
|
||||
|
||||
processTimers(p)
|
||||
|
||||
|
||||
proc connect*(socket: TAsyncFD, address: string, port: Port,
|
||||
af = AF_INET): Future[void] =
|
||||
var retFuture = newFuture[void]("connect")
|
||||
|
||||
|
||||
proc cb(fd: TAsyncFD): bool =
|
||||
# We have connected.
|
||||
retFuture.complete()
|
||||
return true
|
||||
|
||||
|
||||
var aiList = getAddrInfo(address, port, af)
|
||||
var success = false
|
||||
var lastError: OSErrorCode
|
||||
|
|
@ -952,7 +952,7 @@ else:
|
|||
proc recv*(socket: TAsyncFD, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] =
|
||||
var retFuture = newFuture[string]("recv")
|
||||
|
||||
|
||||
var readBuffer = newString(size)
|
||||
|
||||
proc cb(sock: TAsyncFD): bool =
|
||||
|
|
@ -983,9 +983,9 @@ else:
|
|||
proc send*(socket: TAsyncFD, data: string,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||
var retFuture = newFuture[void]("send")
|
||||
|
||||
|
||||
var written = 0
|
||||
|
||||
|
||||
proc cb(sock: TAsyncFD): bool =
|
||||
result = true
|
||||
let netSize = data.len-written
|
||||
|
|
@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
|||
of nnkTryStmt:
|
||||
# try: await x; except: ...
|
||||
result = newNimNode(nnkStmtList, node)
|
||||
template wrapInTry(n, tryBody: PNimrodNode) =
|
||||
template wrapInTry(n, tryBody: expr) =
|
||||
var temp = n
|
||||
n[0] = tryBody
|
||||
tryBody = temp
|
||||
|
|
@ -1315,29 +1315,40 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
if returnType.kind == nnkEmpty: newIdentNode("void")
|
||||
else: returnType[1]
|
||||
outerProcBody.add(
|
||||
newVarStmt(retFutureSym,
|
||||
newVarStmt(retFutureSym,
|
||||
newCall(
|
||||
newNimNode(nnkBracketExpr, prc[6]).add(
|
||||
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
||||
subRetType),
|
||||
newLit(prc[0].getName)))) # Get type from return type of this proc
|
||||
|
||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||
|
||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||
# -> {.push warning[resultshadowed]: off.}
|
||||
# -> var result: T
|
||||
# -> {.pop.}
|
||||
# -> <proc_body>
|
||||
# -> complete(retFuture, result)
|
||||
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
||||
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
||||
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
|
||||
|
||||
procBody.insert(2, newNimNode(nnkPragma).add(
|
||||
newIdentNode("pop"))) # -> {.pop.})
|
||||
|
||||
procBody.add(
|
||||
newCall(newIdentNode("complete"),
|
||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||
else:
|
||||
# -> complete(retFuture)
|
||||
procBody.add(newCall(newIdentNode("complete"), retFutureSym))
|
||||
|
||||
|
||||
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
|
||||
procBody, nnkIteratorDef)
|
||||
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
|
||||
|
|
@ -1351,7 +1362,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
|
||||
# -> return retFuture
|
||||
outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
|
||||
|
||||
|
||||
result = prc
|
||||
|
||||
# Remove the 'async' pragma.
|
||||
|
|
@ -1377,7 +1388,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
|
|||
## If a full line is read ``\r\L`` is not
|
||||
## added to ``line``, however if solely ``\r\L`` is read then ``line``
|
||||
## will be set to it.
|
||||
##
|
||||
##
|
||||
## If the socket is disconnected, ``line`` will be set to ``""``.
|
||||
##
|
||||
## If the socket is disconnected in the middle of a line (before ``\r\L``
|
||||
|
|
@ -1388,7 +1399,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
|
|||
##
|
||||
## **Note**: This procedure is mostly used for testing. You likely want to
|
||||
## use ``asyncnet.recvLine`` instead.
|
||||
|
||||
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements asynchronous file handling.
|
||||
## This module implements asynchronous file reading and writing.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## import asyncfile, asyncdispatch, os
|
||||
|
|
@ -24,17 +24,17 @@
|
|||
|
||||
import asyncdispatch, os
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
import winlean
|
||||
else:
|
||||
import posix
|
||||
|
||||
type
|
||||
AsyncFile = ref object
|
||||
AsyncFile* = ref object
|
||||
fd: TAsyncFd
|
||||
offset: int64
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
proc getDesiredAccess(mode: FileMode): int32 =
|
||||
case mode
|
||||
of fmRead:
|
||||
|
|
@ -70,7 +70,7 @@ else:
|
|||
|
||||
proc getFileSize(f: AsyncFile): int64 =
|
||||
## Retrieves the specified file's size.
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var high: DWord
|
||||
let low = getFileSize(f.fd.THandle, addr high)
|
||||
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
|
||||
## the specified ``mode`` asynchronously.
|
||||
new result
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
||||
let desiredAccess = getDesiredAccess(mode)
|
||||
let creationDisposition = getCreationDisposition(mode, filename)
|
||||
|
|
@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
|||
## returned.
|
||||
var retFuture = newFuture[string]("asyncfile.read")
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var buffer = alloc0(size)
|
||||
|
||||
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
|
||||
## operations. The file's first byte has the index zero.
|
||||
f.offset = pos
|
||||
when not defined(windows):
|
||||
when not defined(windows) and not defined(nimdoc):
|
||||
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
||||
if ret == -1:
|
||||
raiseOSError(osLastError())
|
||||
|
|
@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
|||
## specified file.
|
||||
var retFuture = newFuture[void]("asyncfile.write")
|
||||
var copy = data
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var buffer = alloc0(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) =
|
||||
## Closes the file specified.
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
if not closeHandle(f.fd.THandle).bool:
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
|||
result[i] = itm
|
||||
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] =
|
||||
## 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)
|
||||
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.
|
||||
##
|
||||
## 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)[5] == @[7]
|
||||
assert(not s.isNil, "`s` can't be nil")
|
||||
assert(num > 0, "`num` has to be greater than zero")
|
||||
if num < 2:
|
||||
result = @[s]
|
||||
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.
|
||||
result = newSeq[seq[T]](num)
|
||||
var
|
||||
|
|
@ -587,4 +606,14 @@ when isMainModule:
|
|||
seq2D[0][1] = true
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
|||
var hc: THash
|
||||
var index = rawGet(t, key, hc)
|
||||
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 =
|
||||
## 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)
|
||||
|
||||
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.im = sin(phi)
|
||||
result.im = r * sin(phi)
|
||||
|
||||
|
||||
proc `$`*(z: Complex): string =
|
||||
|
|
@ -438,5 +438,6 @@ when isMainModule:
|
|||
assert( arccoth(a) =~ arctanh(1/a) )
|
||||
|
||||
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) )
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## h = h &! hash(x.foo)
|
||||
## h = h &! hash(x.bar)
|
||||
## h = h !& hash(x.foo)
|
||||
## h = h !& hash(x.bar)
|
||||
## result = !$h
|
||||
|
||||
import
|
||||
|
|
|
|||
|
|
@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
|||
## server takes longer than specified an ETimeout exception will be raised.
|
||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||
var headers = substr(httpMethod, len("http"))
|
||||
# TODO: Use generateHeaders further down once it supports proxies.
|
||||
if proxy == nil:
|
||||
headers.add(" " & r.path)
|
||||
headers.add ' '
|
||||
if r.path[0] != '/': headers.add '/'
|
||||
headers.add(r.path)
|
||||
if r.query.len > 0:
|
||||
headers.add("?" & r.query)
|
||||
else:
|
||||
|
|
@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
|
|||
|
||||
proc generateHeaders(r: Uri, httpMethod: string,
|
||||
headers: StringTableRef): string =
|
||||
# TODO: Use this in the blocking HttpClient once it supports proxies.
|
||||
result = substr(httpMethod, len("http"))
|
||||
# TODO: Proxies
|
||||
result.add(" " & r.path)
|
||||
result.add ' '
|
||||
if r.path[0] != '/': result.add '/'
|
||||
result.add(r.path)
|
||||
if r.query.len > 0:
|
||||
result.add("?" & r.query)
|
||||
result.add(" HTTP/1.1\c\L")
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
|
|||
# ------------- pretty printing ----------------------------------------------
|
||||
|
||||
proc indent(s: var string, i: int) =
|
||||
s.add(repeatChar(i))
|
||||
s.add(spaces(i))
|
||||
|
||||
proc newIndent(curr, indent: int, ml: bool): int =
|
||||
if ml: return curr + indent
|
||||
|
|
|
|||
|
|
@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
|
|||
inc(i)
|
||||
add(result, "\n")
|
||||
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,
|
||||
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],
|
||||
lastError: OSErrorCode): bool =
|
||||
## 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):
|
||||
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)
|
||||
socketError(socket, ret)
|
||||
|
||||
|
|
@ -969,20 +992,6 @@ proc isSsl*(socket: Socket): bool =
|
|||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||
## 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 =
|
||||
## Returns the IPv4 any address, which can be used to listen on all available
|
||||
## network adapters
|
||||
|
|
@ -1241,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
|||
raise newException(ValueError,
|
||||
"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
|
||||
## Raises EInvalidValue on error
|
||||
if address_str == nil:
|
||||
|
|
@ -1250,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
|
|||
return parseIPv6Address(address_str)
|
||||
else:
|
||||
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
|
||||
## lower-level features.
|
||||
##
|
||||
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
|
||||
## module instead as this version has issues with spaces in arguments.
|
||||
{.deprecated.}
|
||||
## Supported syntax:
|
||||
##
|
||||
## 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.}
|
||||
|
||||
include "system/inclrtl"
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
|||
my.kind = xmlError
|
||||
my.a = ""
|
||||
my.b = ""
|
||||
my.c = nil
|
||||
my.options = options
|
||||
|
||||
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
|
||||
return my.kind
|
||||
|
||||
proc charData*(my: XmlParser): string {.inline.} =
|
||||
template charData*(my: XmlParser): string =
|
||||
## returns the character data for the events: ``xmlCharData``,
|
||||
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
||||
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
||||
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``,
|
||||
## ``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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
assert(my.kind == xmlPI)
|
||||
return my.b
|
||||
my.b
|
||||
|
||||
proc rawData*(my: XmlParser): string {.inline.} =
|
||||
## returns the underlying 'data' string by reference.
|
||||
|
|
@ -621,7 +622,7 @@ proc next*(my: var XmlParser) =
|
|||
of stateEmptyElementTag:
|
||||
my.state = stateNormal
|
||||
my.kind = xmlElementEnd
|
||||
if not isNil(my.c):
|
||||
if not my.c.isNil:
|
||||
my.a = my.c
|
||||
of stateError:
|
||||
my.kind = xmlError
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ when useUnicode:
|
|||
const
|
||||
InlineThreshold = 5 ## number of leaves; -1 to disable inlining
|
||||
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
|
||||
PegKind = enum
|
||||
|
|
@ -85,14 +85,14 @@ type
|
|||
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
|
||||
else: sons: seq[TNode]
|
||||
NonTerminal* = ref NonTerminalObj
|
||||
|
||||
|
||||
Peg* = TNode ## type that represents a PEG
|
||||
|
||||
{.deprecated: [TPeg: Peg].}
|
||||
|
||||
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
|
||||
## constructs a PEG from a terminal string
|
||||
if t.len != 1:
|
||||
if t.len != 1:
|
||||
result.kind = pkTerminal
|
||||
result.term = t
|
||||
else:
|
||||
|
|
@ -116,7 +116,7 @@ proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
|
|||
assert t != '\0'
|
||||
result.kind = pkChar
|
||||
result.ch = t
|
||||
|
||||
|
||||
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||
## constructs a PEG from a character set `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) =
|
||||
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!
|
||||
case elem.kind
|
||||
of pkCharChoice:
|
||||
dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
|
||||
of pkChar:
|
||||
of pkChar:
|
||||
dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
|
||||
else: add(dest, elem)
|
||||
else: add(dest, elem)
|
||||
|
|
@ -158,12 +158,12 @@ proc `/`*(a: varargs[Peg]): Peg {.
|
|||
|
||||
proc addSequence(dest: var Peg, elem: Peg) =
|
||||
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!
|
||||
case elem.kind
|
||||
of pkTerminal:
|
||||
of pkTerminal:
|
||||
dest.sons[L] = term(dest.sons[L].term & elem.term)
|
||||
of pkChar:
|
||||
of pkChar:
|
||||
dest.sons[L] = term(dest.sons[L].term & elem.ch)
|
||||
else: add(dest, elem)
|
||||
else: add(dest, elem)
|
||||
|
|
@ -172,7 +172,7 @@ proc sequence*(a: varargs[Peg]): Peg {.
|
|||
nosideEffect, rtl, extern: "npegs$1".} =
|
||||
## constructs a sequence with all the PEGs from `a`
|
||||
multipleOp(pkSequence, addSequence)
|
||||
|
||||
|
||||
proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
|
||||
## constructs an optional for the PEG `a`
|
||||
if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
|
||||
|
|
@ -207,7 +207,7 @@ proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
|
|||
result.kind = pkSearch
|
||||
result.sons = @[a]
|
||||
|
||||
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
||||
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
||||
extern: "npgegsCapturedSearch".} =
|
||||
## constructs a "captured search" for the PEG `a`
|
||||
result.kind = pkCapturedSearch
|
||||
|
|
@ -216,7 +216,7 @@ proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
|||
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
||||
## constructs a "greedy positive repetition" with the PEG `a`
|
||||
return sequence(a, *a)
|
||||
|
||||
|
||||
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
|
||||
## constructs an "and predicate" with the PEG `a`
|
||||
result.kind = pkAndPredicate
|
||||
|
|
@ -239,33 +239,33 @@ proc newLine*: Peg {.inline.} =
|
|||
## constructs the PEG `newline`:idx: (``\n``)
|
||||
result.kind = pkNewLine
|
||||
|
||||
proc unicodeLetter*: Peg {.inline.} =
|
||||
proc unicodeLetter*: Peg {.inline.} =
|
||||
## constructs the PEG ``\letter`` which matches any Unicode letter.
|
||||
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.
|
||||
result.kind = pkUpper
|
||||
|
||||
proc unicodeTitle*: Peg {.inline.} =
|
||||
|
||||
proc unicodeTitle*: Peg {.inline.} =
|
||||
## constructs the PEG ``\title`` which matches any Unicode title letter.
|
||||
result.kind = pkTitle
|
||||
|
||||
proc unicodeWhitespace*: Peg {.inline.} =
|
||||
## constructs the PEG ``\white`` which matches any Unicode
|
||||
proc unicodeWhitespace*: Peg {.inline.} =
|
||||
## constructs the PEG ``\white`` which matches any Unicode
|
||||
## whitespace character.
|
||||
result.kind = pkWhitespace
|
||||
|
||||
proc startAnchor*: Peg {.inline.} =
|
||||
## constructs the PEG ``^`` which matches the start of the input.
|
||||
proc startAnchor*: Peg {.inline.} =
|
||||
## constructs the PEG ``^`` which matches the start of the input.
|
||||
result.kind = pkStartAnchor
|
||||
|
||||
proc endAnchor*: Peg {.inline.} =
|
||||
## constructs the PEG ``$`` which matches the end of the input.
|
||||
proc endAnchor*: Peg {.inline.} =
|
||||
## constructs the PEG ``$`` which matches the end of the input.
|
||||
result = !any()
|
||||
|
||||
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]
|
||||
|
||||
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
|
||||
## from 1.
|
||||
result.kind = pkBackRef
|
||||
result.index = index-1
|
||||
|
||||
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
|
||||
## from 1. Ignores case for matching.
|
||||
result.kind = pkBackRefIgnoreCase
|
||||
result.index = index-1
|
||||
|
||||
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
|
||||
## from 1. Ignores style for matching.
|
||||
result.kind = pkBackRefIgnoreStyle
|
||||
|
|
@ -298,7 +298,7 @@ proc spaceCost(n: Peg): int =
|
|||
case n.kind
|
||||
of pkEmpty: discard
|
||||
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
|
||||
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
||||
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
||||
pkAny..pkWhitespace, pkGreedyAny:
|
||||
result = 1
|
||||
of pkNonTerminal:
|
||||
|
|
@ -310,7 +310,7 @@ proc spaceCost(n: Peg): int =
|
|||
if result >= InlineThreshold: break
|
||||
|
||||
proc nonterminal*(n: NonTerminal): Peg {.
|
||||
nosideEffect, rtl, extern: "npegs$1".} =
|
||||
nosideEffect, rtl, extern: "npegs$1".} =
|
||||
## constructs a PEG that consists of the nonterminal symbol
|
||||
assert n != nil
|
||||
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 =
|
||||
## expands to ``charset({'A'..'Z', 'a'..'z'})``
|
||||
charSet({'A'..'Z', 'a'..'z'})
|
||||
|
||||
|
||||
template digits*: expr =
|
||||
## expands to ``charset({'0'..'9'})``
|
||||
charSet({'0'..'9'})
|
||||
|
|
@ -339,11 +339,11 @@ template digits*: expr =
|
|||
template whitespace*: expr =
|
||||
## expands to ``charset({' ', '\9'..'\13'})``
|
||||
charSet({' ', '\9'..'\13'})
|
||||
|
||||
|
||||
template identChars*: expr =
|
||||
## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
|
||||
charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
|
||||
|
||||
|
||||
template identStartChars*: expr =
|
||||
## expands to ``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
|
||||
sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
|
||||
*charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
|
||||
|
||||
|
||||
template natural*: expr =
|
||||
## same as ``\d+``
|
||||
+digits
|
||||
|
||||
# ------------------------- debugging -----------------------------------------
|
||||
|
||||
proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
||||
proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
||||
case c
|
||||
of '\b': result = "\\b"
|
||||
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 in reserved: result = '\\' & c
|
||||
else: result = $c
|
||||
|
||||
|
||||
proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
|
||||
|
||||
proc singleQuoteEsc(str: string): string =
|
||||
proc singleQuoteEsc(str: string): string =
|
||||
result = "'"
|
||||
for c in items(str): add result, esc(c, {'\''})
|
||||
add result, '\''
|
||||
|
||||
proc charSetEscAux(cc: set[char]): string =
|
||||
|
||||
proc charSetEscAux(cc: set[char]): string =
|
||||
const reserved = {'^', '-', ']'}
|
||||
result = ""
|
||||
var c1 = 0
|
||||
while c1 <= 0xff:
|
||||
if chr(c1) in cc:
|
||||
while c1 <= 0xff:
|
||||
if chr(c1) in cc:
|
||||
var c2 = c1
|
||||
while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
|
||||
if c1 == c2:
|
||||
if c1 == c2:
|
||||
add result, esc(chr(c1), reserved)
|
||||
elif c2 == succ(c1):
|
||||
elif c2 == succ(c1):
|
||||
add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
|
||||
else:
|
||||
else:
|
||||
add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
|
||||
c1 = c2
|
||||
inc(c1)
|
||||
|
||||
|
||||
proc charSetEsc(cc: set[char]): string =
|
||||
if card(cc) >= 128+64:
|
||||
if card(cc) >= 128+64:
|
||||
result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
|
||||
else:
|
||||
else:
|
||||
result = '[' & charSetEscAux(cc) & ']'
|
||||
|
||||
proc toStrAux(r: Peg, res: var string) =
|
||||
|
||||
proc toStrAux(r: Peg, res: var string) =
|
||||
case r.kind
|
||||
of pkEmpty: add(res, "()")
|
||||
of pkAny: add(res, '.')
|
||||
|
|
@ -469,25 +469,25 @@ proc toStrAux(r: Peg, res: var string) =
|
|||
toStrAux(r.sons[0], res)
|
||||
of pkCapture:
|
||||
add(res, '{')
|
||||
toStrAux(r.sons[0], res)
|
||||
toStrAux(r.sons[0], res)
|
||||
add(res, '}')
|
||||
of pkBackRef:
|
||||
of pkBackRef:
|
||||
add(res, '$')
|
||||
add(res, $r.index)
|
||||
of pkBackRefIgnoreCase:
|
||||
of pkBackRefIgnoreCase:
|
||||
add(res, "i$")
|
||||
add(res, $r.index)
|
||||
of pkBackRefIgnoreStyle:
|
||||
of pkBackRefIgnoreStyle:
|
||||
add(res, "y$")
|
||||
add(res, $r.index)
|
||||
of pkRule:
|
||||
toStrAux(r.sons[0], res)
|
||||
toStrAux(r.sons[0], res)
|
||||
add(res, " <- ")
|
||||
toStrAux(r.sons[1], res)
|
||||
of pkList:
|
||||
for i in 0 .. high(r.sons):
|
||||
toStrAux(r.sons[i], res)
|
||||
add(res, "\n")
|
||||
add(res, "\n")
|
||||
of pkStartAnchor:
|
||||
add(res, '^')
|
||||
|
||||
|
|
@ -506,8 +506,8 @@ type
|
|||
|
||||
{.deprecated: [TCaptures: Captures].}
|
||||
|
||||
proc bounds*(c: Captures,
|
||||
i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
|
||||
proc bounds*(c: Captures,
|
||||
i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
|
||||
## returns the bounds ``[first..last]`` of the `i`'th capture.
|
||||
result = c.matches[i]
|
||||
|
||||
|
|
@ -527,7 +527,7 @@ when not useUnicode:
|
|||
|
||||
proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
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
|
||||
## proc).
|
||||
## 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)
|
||||
else:
|
||||
result = -1
|
||||
of pkLetter:
|
||||
of pkLetter:
|
||||
if s[start] != '\0':
|
||||
var a: Rune
|
||||
result = start
|
||||
|
|
@ -550,7 +550,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
|||
else: result = -1
|
||||
else:
|
||||
result = -1
|
||||
of pkLower:
|
||||
of pkLower:
|
||||
if s[start] != '\0':
|
||||
var a: Rune
|
||||
result = start
|
||||
|
|
@ -559,7 +559,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
|||
else: result = -1
|
||||
else:
|
||||
result = -1
|
||||
of pkUpper:
|
||||
of pkUpper:
|
||||
if s[start] != '\0':
|
||||
var a: Rune
|
||||
result = start
|
||||
|
|
@ -568,16 +568,16 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
|||
else: result = -1
|
||||
else:
|
||||
result = -1
|
||||
of pkTitle:
|
||||
of pkTitle:
|
||||
if s[start] != '\0':
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
if isTitle(a): dec(result, start)
|
||||
if isTitle(a): dec(result, start)
|
||||
else: result = -1
|
||||
else:
|
||||
result = -1
|
||||
of pkWhitespace:
|
||||
of pkWhitespace:
|
||||
if s[start] != '\0':
|
||||
var a: Rune
|
||||
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
|
||||
if result < 0: c.ml = oldMl
|
||||
of pkSequence:
|
||||
var oldMl = c.ml
|
||||
var oldMl = c.ml
|
||||
result = 0
|
||||
for i in 0..high(p.sons):
|
||||
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:
|
||||
c.ml = idx
|
||||
of pkBackRef..pkBackRefIgnoreStyle:
|
||||
of pkBackRef..pkBackRefIgnoreStyle:
|
||||
if p.index >= c.ml: return -1
|
||||
var (a, b) = c.matches[p.index]
|
||||
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)
|
||||
result = rawMatch(s, n, start, c)
|
||||
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
|
||||
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".} =
|
||||
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
|
||||
var c: Captures
|
||||
|
|
@ -773,7 +773,7 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
|
|||
result = rawMatch(s, pattern, start, 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".} =
|
||||
## 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
|
||||
|
|
@ -797,11 +797,11 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string],
|
|||
return i
|
||||
return -1
|
||||
# could also use the pattern here: (!P .)* P
|
||||
|
||||
|
||||
proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
|
||||
start = 0): tuple[first, last: int] {.
|
||||
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
|
||||
## substrings in the array ``matches``. If it does not match, nothing
|
||||
## 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)
|
||||
return (i, i+L-1)
|
||||
return (-1, 0)
|
||||
|
||||
proc find*(s: string, pattern: Peg,
|
||||
|
||||
proc find*(s: string, pattern: Peg,
|
||||
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||
## returns the starting position of ``pattern`` in ``s``. If it does not
|
||||
## match, -1 is returned.
|
||||
|
|
@ -824,8 +824,8 @@ proc find*(s: string, pattern: Peg,
|
|||
for i in start .. s.len-1:
|
||||
if rawMatch(s, pattern, i, c) >= 0: return i
|
||||
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`.
|
||||
var c: Captures
|
||||
c.origStart = start
|
||||
|
|
@ -838,23 +838,23 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string =
|
|||
else:
|
||||
yield substr(s, i, i+L-1)
|
||||
inc(i, L)
|
||||
|
||||
|
||||
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`.
|
||||
## If it does not match, @[] is returned.
|
||||
accumulateResult(findAll(s, pattern, start))
|
||||
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
|
||||
template `=~`*(s: string, pattern: Peg): bool =
|
||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||
## can be used in the scope of the ``=~`` call:
|
||||
##
|
||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||
## can be used in the scope of the ``=~`` call:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
|
||||
## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
|
||||
## # matches a key=value pair:
|
||||
## echo("Key: ", matches[0])
|
||||
## echo("Value: ", matches[1])
|
||||
|
|
@ -865,7 +865,7 @@ template `=~`*(s: string, pattern: Peg): bool =
|
|||
## echo("comment: ", matches[0])
|
||||
## else:
|
||||
## echo("syntax error")
|
||||
##
|
||||
##
|
||||
bind MaxSubpatterns
|
||||
when not declaredInScope(matches):
|
||||
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:
|
||||
##
|
||||
## .. 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:
|
||||
##
|
||||
|
|
@ -941,10 +941,10 @@ proc replace*(s: string, sub: Peg, by = ""): string {.
|
|||
add(result, by)
|
||||
inc(i, x)
|
||||
add(result, substr(s, i))
|
||||
|
||||
|
||||
proc parallelReplace*(s: string, subs: varargs[
|
||||
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`
|
||||
## applied in parallel.
|
||||
result = ""
|
||||
|
|
@ -964,8 +964,8 @@ proc parallelReplace*(s: string, subs: varargs[
|
|||
add(result, s[i])
|
||||
inc(i)
|
||||
# copy the rest:
|
||||
add(result, substr(s, i))
|
||||
|
||||
add(result, substr(s, i))
|
||||
|
||||
proc transformFile*(infile, outfile: string,
|
||||
subs: varargs[tuple[pattern: Peg, repl: string]]) {.
|
||||
rtl, extern: "npegs$1".} =
|
||||
|
|
@ -974,7 +974,7 @@ proc transformFile*(infile, outfile: string,
|
|||
## error occurs. This is supposed to be used for quick scripting.
|
||||
var x = readFile(infile).string
|
||||
writeFile(outfile, x.parallelReplace(subs))
|
||||
|
||||
|
||||
iterator split*(s: string, sep: Peg): string =
|
||||
## Splits the string `s` into substrings.
|
||||
##
|
||||
|
|
@ -1049,14 +1049,14 @@ type
|
|||
tkBackref, ## '$'
|
||||
tkDollar, ## '$'
|
||||
tkHat ## '^'
|
||||
|
||||
|
||||
TToken {.final.} = object ## a token
|
||||
kind: TTokKind ## the type of the token
|
||||
modifier: TModifier
|
||||
literal: string ## the parsed (string) literal
|
||||
charset: set[char] ## if kind == tkCharSet
|
||||
index: int ## if kind == tkBackref
|
||||
|
||||
|
||||
PegLexer {.inheritable.} = object ## the lexer object.
|
||||
bufpos: int ## the current position within the buffer
|
||||
buf: cstring ## the buffer itself
|
||||
|
|
@ -1086,7 +1086,7 @@ proc handleLF(L: var PegLexer, pos: int): int =
|
|||
result = pos+1
|
||||
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.bufpos = 0
|
||||
L.lineNumber = line
|
||||
|
|
@ -1094,69 +1094,69 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
|
|||
L.lineStart = 0
|
||||
L.filename = filename
|
||||
|
||||
proc getColumn(L: PegLexer): int {.inline.} =
|
||||
proc getColumn(L: PegLexer): int {.inline.} =
|
||||
result = abs(L.bufpos - L.lineStart) + L.colOffset
|
||||
|
||||
proc getLine(L: PegLexer): int {.inline.} =
|
||||
proc getLine(L: PegLexer): int {.inline.} =
|
||||
result = L.lineNumber
|
||||
|
||||
|
||||
proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
|
||||
var line = if line < 0: getLine(L) else: line
|
||||
var col = if col < 0: getColumn(L) else: col
|
||||
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]
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
|
||||
inc(c.bufpos)
|
||||
of 'a'..'f':
|
||||
of 'a'..'f':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
|
||||
inc(c.bufpos)
|
||||
of 'A'..'F':
|
||||
of 'A'..'F':
|
||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
||||
inc(c.bufpos)
|
||||
else: discard
|
||||
|
||||
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
||||
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
||||
inc(c.bufpos)
|
||||
case c.buf[c.bufpos]
|
||||
of 'r', 'R', 'c', 'C':
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, '\c')
|
||||
inc(c.bufpos)
|
||||
of 'l', 'L':
|
||||
of 'l', 'L':
|
||||
add(tok.literal, '\L')
|
||||
inc(c.bufpos)
|
||||
of 'f', 'F':
|
||||
of 'f', 'F':
|
||||
add(tok.literal, '\f')
|
||||
inc(c.bufpos)
|
||||
of 'e', 'E':
|
||||
of 'e', 'E':
|
||||
add(tok.literal, '\e')
|
||||
inc(c.bufpos)
|
||||
of 'a', 'A':
|
||||
of 'a', 'A':
|
||||
add(tok.literal, '\a')
|
||||
inc(c.bufpos)
|
||||
of 'b', 'B':
|
||||
of 'b', 'B':
|
||||
add(tok.literal, '\b')
|
||||
inc(c.bufpos)
|
||||
of 'v', 'V':
|
||||
of 'v', 'V':
|
||||
add(tok.literal, '\v')
|
||||
inc(c.bufpos)
|
||||
of 't', 'T':
|
||||
of 't', 'T':
|
||||
add(tok.literal, '\t')
|
||||
inc(c.bufpos)
|
||||
of 'x', 'X':
|
||||
of 'x', 'X':
|
||||
inc(c.bufpos)
|
||||
var xi = 0
|
||||
handleHexChar(c, xi)
|
||||
handleHexChar(c, xi)
|
||||
if xi == 0: tok.kind = tkInvalid
|
||||
else: add(tok.literal, chr(xi))
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
var val = ord(c.buf[c.bufpos]) - ord('0')
|
||||
inc(c.bufpos)
|
||||
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')
|
||||
inc(c.bufpos)
|
||||
inc(i)
|
||||
|
|
@ -1169,32 +1169,32 @@ proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
|||
else:
|
||||
add(tok.literal, c.buf[c.bufpos])
|
||||
inc(c.bufpos)
|
||||
|
||||
proc skip(c: var PegLexer) =
|
||||
|
||||
proc skip(c: var PegLexer) =
|
||||
var pos = c.bufpos
|
||||
var buf = c.buf
|
||||
while true:
|
||||
while true:
|
||||
case buf[pos]
|
||||
of ' ', '\t':
|
||||
of ' ', '\t':
|
||||
inc(pos)
|
||||
of '#':
|
||||
while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
|
||||
of '\c':
|
||||
pos = handleCR(c, pos)
|
||||
buf = c.buf
|
||||
of '\L':
|
||||
of '\L':
|
||||
pos = handleLF(c, pos)
|
||||
buf = c.buf
|
||||
else:
|
||||
else:
|
||||
break # EndOfFile also leaves the loop
|
||||
c.bufpos = pos
|
||||
|
||||
proc getString(c: var PegLexer, tok: var TToken) =
|
||||
|
||||
proc getString(c: var PegLexer, tok: var TToken) =
|
||||
tok.kind = tkStringLit
|
||||
var pos = c.bufpos + 1
|
||||
var buf = c.buf
|
||||
var quote = buf[pos-1]
|
||||
while true:
|
||||
while true:
|
||||
case buf[pos]
|
||||
of '\\':
|
||||
c.bufpos = pos
|
||||
|
|
@ -1205,13 +1205,13 @@ proc getString(c: var PegLexer, tok: var TToken) =
|
|||
break
|
||||
elif buf[pos] == quote:
|
||||
inc(pos)
|
||||
break
|
||||
break
|
||||
else:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(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 buf = c.buf
|
||||
if buf[pos] in {'0'..'9'}:
|
||||
|
|
@ -1223,8 +1223,8 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
|
|||
else:
|
||||
tok.kind = tkDollar
|
||||
c.bufpos = pos
|
||||
|
||||
proc getCharSet(c: var PegLexer, tok: var TToken) =
|
||||
|
||||
proc getCharSet(c: var PegLexer, tok: var TToken) =
|
||||
tok.kind = tkCharSet
|
||||
tok.charset = {}
|
||||
var pos = c.bufpos + 1
|
||||
|
|
@ -1247,7 +1247,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
|
|||
of '\C', '\L', '\0':
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
else:
|
||||
else:
|
||||
ch = buf[pos]
|
||||
inc(pos)
|
||||
incl(tok.charset, ch)
|
||||
|
|
@ -1267,18 +1267,18 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
|
|||
of '\C', '\L', '\0':
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
else:
|
||||
else:
|
||||
ch2 = buf[pos]
|
||||
inc(pos)
|
||||
for i in ord(ch)+1 .. ord(ch2):
|
||||
incl(tok.charset, chr(i))
|
||||
c.bufpos = pos
|
||||
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 buf = c.buf
|
||||
while true:
|
||||
while true:
|
||||
add(tok.literal, buf[pos])
|
||||
inc(pos)
|
||||
if buf[pos] notin strutils.IdentChars: break
|
||||
|
|
@ -1294,7 +1294,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
|
|||
tok.kind = tkEscaped
|
||||
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.modifier = modNone
|
||||
setLen(tok.literal, 0)
|
||||
|
|
@ -1309,11 +1309,11 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
|||
else:
|
||||
tok.kind = tkCurlyLe
|
||||
add(tok.literal, '{')
|
||||
of '}':
|
||||
of '}':
|
||||
tok.kind = tkCurlyRi
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, '}')
|
||||
of '[':
|
||||
of '[':
|
||||
getCharSet(c, tok)
|
||||
of '(':
|
||||
tok.kind = tkParLe
|
||||
|
|
@ -1323,7 +1323,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
|||
tok.kind = tkParRi
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, ')')
|
||||
of '.':
|
||||
of '.':
|
||||
tok.kind = tkAny
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, '.')
|
||||
|
|
@ -1331,16 +1331,16 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
|||
tok.kind = tkAnyRune
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, '_')
|
||||
of '\\':
|
||||
of '\\':
|
||||
getBuiltin(c, tok)
|
||||
of '\'', '"': getString(c, tok)
|
||||
of '$': getDollar(c, tok)
|
||||
of '\0':
|
||||
of '\0':
|
||||
tok.kind = tkEof
|
||||
tok.literal = "[EOF]"
|
||||
of 'a'..'z', 'A'..'Z', '\128'..'\255':
|
||||
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'}:
|
||||
case tok.literal
|
||||
of "i": tok.modifier = modIgnoreCase
|
||||
|
|
@ -1388,7 +1388,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
|||
tok.kind = tkAt
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, '@')
|
||||
if c.buf[c.bufpos] == '@':
|
||||
if c.buf[c.bufpos] == '@':
|
||||
tok.kind = tkCurlyAt
|
||||
inc(c.bufpos)
|
||||
add(tok.literal, '@')
|
||||
|
|
@ -1407,7 +1407,7 @@ proc arrowIsNextTok(c: PegLexer): bool =
|
|||
result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
|
||||
|
||||
# ----------------------------- parser ----------------------------------------
|
||||
|
||||
|
||||
type
|
||||
EInvalidPeg* = object of ValueError ## raised if an invalid
|
||||
## 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)
|
||||
raise e
|
||||
|
||||
proc getTok(p: var PegParser) =
|
||||
proc getTok(p: var PegParser) =
|
||||
getTok(p, p.tok)
|
||||
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
|
||||
|
||||
|
|
@ -1475,7 +1475,7 @@ proc builtin(p: var PegParser): Peg =
|
|||
of "white": result = unicodeWhitespace()
|
||||
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
|
||||
else: result = sequence(p.skip, terminal)
|
||||
|
||||
|
|
@ -1496,7 +1496,7 @@ proc primary(p: var PegParser): Peg =
|
|||
else: discard
|
||||
case p.tok.kind
|
||||
of tkIdentifier:
|
||||
if p.identIsVerbatim:
|
||||
if p.identIsVerbatim:
|
||||
var m = p.tok.modifier
|
||||
if m == modNone: m = p.modifier
|
||||
result = modifiedTerm(p.tok.literal, m).token(p)
|
||||
|
|
@ -1539,17 +1539,17 @@ proc primary(p: var PegParser): Peg =
|
|||
of tkEscaped:
|
||||
result = term(p.tok.literal[0]).token(p)
|
||||
getTok(p)
|
||||
of tkDollar:
|
||||
of tkDollar:
|
||||
result = endAnchor()
|
||||
getTok(p)
|
||||
of tkHat:
|
||||
of tkHat:
|
||||
result = startAnchor()
|
||||
getTok(p)
|
||||
of tkBackref:
|
||||
var m = p.tok.modifier
|
||||
if m == modNone: m = p.modifier
|
||||
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)
|
||||
getTok(p)
|
||||
else:
|
||||
|
|
@ -1573,7 +1573,7 @@ proc seqExpr(p: var PegParser): Peg =
|
|||
while true:
|
||||
case p.tok.kind
|
||||
of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
|
||||
tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
|
||||
tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
|
||||
tkHat, tkCurlyAt:
|
||||
result = sequence(result, primary(p))
|
||||
of tkIdentifier:
|
||||
|
|
@ -1587,7 +1587,7 @@ proc parseExpr(p: var PegParser): Peg =
|
|||
while p.tok.kind == tkBar:
|
||||
getTok(p)
|
||||
result = result / seqExpr(p)
|
||||
|
||||
|
||||
proc parseRule(p: var PegParser): NonTerminal =
|
||||
if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
|
||||
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
|
||||
else:
|
||||
pegError(p, "rule expected, but found: " & p.tok.literal)
|
||||
|
||||
|
||||
proc rawParse(p: var PegParser): Peg =
|
||||
## parses a rule or a PEG expression
|
||||
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_Le", peg"\y v'while'"))
|
||||
assert match("W_HI_Le", peg"y'while'")
|
||||
|
||||
|
||||
assert($ +digits == $peg"\d+")
|
||||
assert "0158787".match(peg"\d+")
|
||||
assert "ABC 0232".match(peg"\w+\s+\d+")
|
||||
|
|
@ -1693,14 +1693,14 @@ when isMainModule:
|
|||
|
||||
var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
|
||||
assert matchLen("key1= cal9", pattern) == 11
|
||||
|
||||
|
||||
var ws = newNonTerminal("ws", 1, 1)
|
||||
ws.rule = *whitespace
|
||||
|
||||
|
||||
var expr = newNonTerminal("expr", 1, 1)
|
||||
expr.rule = sequence(capture(ident), *sequence(
|
||||
nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
|
||||
|
||||
|
||||
var c: Captures
|
||||
var s = "a+b + c +d+e+f"
|
||||
assert rawMatch(s, expr.rule, 0, c) == len(s)
|
||||
|
|
@ -1722,7 +1722,7 @@ when isMainModule:
|
|||
assert matches[0] == "abc"
|
||||
else:
|
||||
assert false
|
||||
|
||||
|
||||
var g2 = peg"""S <- A B / C D
|
||||
A <- 'a'+
|
||||
B <- 'b'+
|
||||
|
|
@ -1753,13 +1753,13 @@ when isMainModule:
|
|||
|
||||
for x in findAll("abcdef", peg"^{.}", 3):
|
||||
assert x == "d"
|
||||
|
||||
|
||||
if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
|
||||
assert matches[0] == "f"
|
||||
assert matches[1] == "a, b"
|
||||
else:
|
||||
assert false
|
||||
|
||||
|
||||
assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
|
||||
# ß is not a lower cased letter?!
|
||||
assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
|
||||
|
|
|
|||
|
|
@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
|
|||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
|||
|
||||
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||
var s = StringStream(s)
|
||||
if bufLen > 0:
|
||||
setLen(s.data, s.data.len + bufLen)
|
||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||
inc(s.pos, bufLen)
|
||||
if bufLen <= 0:
|
||||
return
|
||||
if s.pos + bufLen > s.data.len:
|
||||
setLen(s.data, s.pos + bufLen)
|
||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||
inc(s.pos, bufLen)
|
||||
|
||||
proc ssClose(s: Stream) =
|
||||
var s = StringStream(s)
|
||||
|
|
|
|||
|
|
@ -499,26 +499,47 @@ proc parseEnum*[T: enum](s: string, default: T): T =
|
|||
return e
|
||||
result = default
|
||||
|
||||
proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
|
||||
proc repeat*(c: char, count: int): string {.noSideEffect,
|
||||
rtl, extern: "nsuRepeatChar".} =
|
||||
## Returns a string of length `count` consisting only of
|
||||
## the character `c`. You can use this proc to left align strings. Example:
|
||||
##
|
||||
## .. 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
|
||||
## width = 15
|
||||
## text1 = "Hello user!"
|
||||
## text2 = "This is a very long string"
|
||||
## echo text1 & repeatChar(max(0, width - text1.len)) & "|"
|
||||
## echo text2 & repeatChar(max(0, width - text2.len)) & "|"
|
||||
result = newString(count)
|
||||
for i in 0..count-1: result[i] = c
|
||||
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||
|
||||
proc repeatStr*(count: int, s: string): string {.noSideEffect,
|
||||
rtl, extern: "nsuRepeatStr".} =
|
||||
## Returns `s` concatenated `count` times.
|
||||
result = newStringOfCap(count*s.len)
|
||||
for i in 0..count-1: result.add(s)
|
||||
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
|
||||
## deprecated: use repeat() or spaces()
|
||||
|
||||
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
|
||||
## deprecated: use repeat(string, count) or string.repeat(count)
|
||||
|
||||
proc align*(s: string, count: int, padding = ' '): string {.
|
||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
|||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
else:
|
||||
import termios, unsigned
|
||||
|
||||
|
|
@ -344,7 +343,7 @@ proc isatty*(f: File): bool =
|
|||
else:
|
||||
proc isatty(fildes: FileHandle): cint {.
|
||||
importc: "_isatty", header: "<io.h>".}
|
||||
|
||||
|
||||
result = isatty(getFileHandle(f)) != 0'i32
|
||||
|
||||
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"resetAttributes"))
|
||||
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal.
|
||||
when defined(windows):
|
||||
result = winGetch().char
|
||||
else:
|
||||
when not defined(windows):
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal. This is not available for
|
||||
## Windows.
|
||||
let fd = getFileHandle(stdin)
|
||||
var oldMode: Termios
|
||||
discard fd.tcgetattr(addr oldMode)
|
||||
|
|
@ -387,5 +385,5 @@ when isMainModule:
|
|||
setForeGroundColor(fgBlue)
|
||||
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
|
||||
if fr < 0: fr = 0
|
||||
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)
|
||||
of "yyy":
|
||||
var fr = ($info.year).len()-3
|
||||
if fr < 0: fr = 0
|
||||
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)
|
||||
of "yyyy":
|
||||
var fr = ($info.year).len()-4
|
||||
if fr < 0: fr = 0
|
||||
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)
|
||||
of "yyyyy":
|
||||
var fr = ($info.year).len()-5
|
||||
if fr < 0: fr = 0
|
||||
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)
|
||||
of "z":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
|
|
|||
|
|
@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
|
|||
elif i <=% 0x07FF:
|
||||
result = newString(2)
|
||||
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:
|
||||
result = newString(3)
|
||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||
result[1] = chr(i shr 6 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[0] = chr(i shr 18 or 0b1111_0000)
|
||||
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[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:
|
||||
result = newString(1)
|
||||
result[0] = chr(i)
|
||||
discard # error, exception?
|
||||
|
||||
proc `$`*(rune: Rune): string =
|
||||
## converts a rune to a string
|
||||
|
|
|
|||
|
|
@ -285,6 +285,16 @@ proc `$`*(u: Uri): string =
|
|||
result.add(u.anchor)
|
||||
|
||||
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:
|
||||
let str = "http://localhost:8080/test"
|
||||
let test = parseUri(str)
|
||||
|
|
|
|||
|
|
@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
|
|||
else: result.add(c)
|
||||
|
||||
proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||
result = repeatChar(indent, ' ') & "<" & n.nodeName
|
||||
result = spaces(indent) & "<" & n.nodeName
|
||||
if not isNil(n.attributes):
|
||||
for i in items(n.attributes):
|
||||
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
||||
|
|
@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
|
|||
of ElementNode:
|
||||
result.add(nodeToXml(i, indent + 2))
|
||||
of TextNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add(addEscaped(i.nodeValue))
|
||||
of CDataSectionNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||
of ProcessingInstructionNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<?" & PProcessingInstruction(i).target & " " &
|
||||
PProcessingInstruction(i).data & " ?>")
|
||||
of CommentNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<!-- " & i.nodeValue & " -->")
|
||||
else:
|
||||
continue
|
||||
result.add("\n")
|
||||
# Add the ending tag - </tag>
|
||||
result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
|
||||
result.add(spaces(indent) & "</" & n.nodeName & ">")
|
||||
|
||||
proc `$`*(doc: PDocument): string =
|
||||
## 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
|
||||
## type class matching all ordinal types; however this includes enums with
|
||||
## holes.
|
||||
|
||||
|
||||
SomeReal* = float|float32|float64
|
||||
## 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
|
||||
## the object! This means that for each object of type `T` the finalizer
|
||||
## will be called!
|
||||
|
||||
|
||||
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
||||
## resets an object `obj` to its initial (binary zero) value. This needs to
|
||||
## be called before any possible `object branch transition`:idx:.
|
||||
|
|
@ -348,7 +348,7 @@ type
|
|||
## This field is filled automatically in the
|
||||
## ``raise`` statement.
|
||||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||
## providing an exception message
|
||||
## providing an exception message
|
||||
## is bad style.
|
||||
trace: string
|
||||
|
||||
|
|
@ -483,7 +483,7 @@ type
|
|||
|
||||
E_Base: Exception, ESystem: SystemError, EIO: IOError,
|
||||
EOS: OSError, EInvalidLibrary: LibraryError,
|
||||
EResourceExhausted: ResourceExhaustedError,
|
||||
EResourceExhausted: ResourceExhaustedError,
|
||||
EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
|
||||
EOverflow: OverflowError, EAccessViolation: AccessViolationError,
|
||||
EAssertionFailed: AssertionError, EInvalidValue: ValueError,
|
||||
|
|
@ -494,7 +494,7 @@ type
|
|||
EInvalidObjectAssignment: ObjectAssignmentError,
|
||||
EInvalidObjectConversion: ObjectConversionError,
|
||||
EDeadThread: DeadThreadError,
|
||||
EFloatInexact: FloatInexactError,
|
||||
EFloatInexact: FloatInexactError,
|
||||
EFloatUnderflow: FloatUnderflowError,
|
||||
EFloatingPoint: FloatingPointError,
|
||||
EFloatInvalidOp: FloatInvalidOpError,
|
||||
|
|
@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
|
|||
|
||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
||||
## unary ``<`` that can be used for nice looking excluding ranges:
|
||||
##
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## 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.}
|
||||
## 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
|
||||
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
|
||||
## short notation for: ``x = pred(x, y)``.
|
||||
|
||||
|
||||
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
||||
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
||||
## 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.}
|
||||
## 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.}
|
||||
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
||||
## 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.
|
||||
## This implements modulo arithmetic.
|
||||
## No overflow errors are possible.
|
||||
|
||||
|
||||
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
|
||||
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
|
||||
## 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.}
|
||||
## Checks if T is of the same type as S
|
||||
##
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## proc test[T](a: T): 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] {.
|
||||
magic: "ArrToSeq", nosideeffect.}
|
||||
## 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]``.
|
||||
|
||||
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.
|
||||
## If the current length is greater than the new length,
|
||||
## ``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) {.
|
||||
magic: "SetLengthStr", noSideEffect.}
|
||||
## sets the length of `s` to `newlen`.
|
||||
## If the current length is greater than the new length,
|
||||
## ``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 {.
|
||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||
|
|
@ -953,7 +953,7 @@ proc newString*(len: int): string {.
|
|||
proc newStringOfCap*(cap: int): string {.
|
||||
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
|
||||
## 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``.
|
||||
|
||||
proc `&` * (x: string, y: char): string {.
|
||||
|
|
@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {.
|
|||
## assert('a' & "bc" == "abc")
|
||||
|
||||
# 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.}
|
||||
## 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:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## when compileOption("floatchecks"):
|
||||
## when compileOption("floatchecks"):
|
||||
## echo "compiled with floating point NaN and Inf checks"
|
||||
|
||||
|
||||
proc compileOption*(option, arg: string): bool {.
|
||||
magic: "CompileOptionArg", noSideEffect.}
|
||||
## can be used to determine an enum compile-time option. Example:
|
||||
##
|
||||
## .. 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"
|
||||
|
||||
const
|
||||
|
|
@ -1056,16 +1056,16 @@ const
|
|||
taintMode = compileOption("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
|
||||
## ``string`` if the taint mode is not
|
||||
## turned on. Use the ``-d:taintMode``
|
||||
## command line switch to turn the taint
|
||||
## mode on.
|
||||
|
||||
|
||||
proc len*(s: TaintedString): int {.borrow.}
|
||||
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
|
||||
## ``string`` if the taint mode is not
|
||||
## 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".}
|
||||
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
||||
## 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
|
||||
## 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`.
|
||||
## This is an O(1) operation.
|
||||
let xl = x.len
|
||||
shallowCopy(x[i], 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.
|
||||
## This is an O(n) operation.
|
||||
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)
|
||||
|
||||
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`.
|
||||
let xl = x.len
|
||||
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
|
||||
## high value is large enough to disable bounds checking in practice.
|
||||
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
|
||||
|
||||
|
||||
PFloat32* = ptr float32 ## an alias for ``ptr float32``
|
||||
PFloat64* = ptr float64 ## an alias for ``ptr float64``
|
||||
PInt64* = ptr int64 ## an alias for ``ptr int64``
|
||||
|
|
@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
|
|||
proc copy*(s: string, first = 0): string {.
|
||||
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
|
||||
proc copy*(s: string, first, last: int): string {.
|
||||
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
||||
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
||||
deprecated.}
|
||||
## copies a slice of `s` into a new string and returns this new
|
||||
## 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!
|
||||
## Use `createShared` to allocate from a shared heap.
|
||||
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.}
|
||||
## 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
|
||||
|
|
@ -1381,7 +1381,7 @@ when not defined(nimrodVM):
|
|||
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||
## free the memory a leak occurs; if one tries to access freed
|
||||
## 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!
|
||||
## Use `deallocShared` to deallocate from a shared heap.
|
||||
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
|
||||
## least ``size`` bytes. The block has to be freed with
|
||||
## ``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!
|
||||
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
||||
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
||||
benign.} =
|
||||
## allocates a new memory block on the shared heap with at
|
||||
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||
## ``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!
|
||||
cast[ptr T](allocShared(T.sizeof * size))
|
||||
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
|
||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||
## The block is initialized with all bytes
|
||||
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||
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
|
||||
## ``resizeShared(block, 0)`` or ``freeShared(block)``.
|
||||
## The block is initialized with all bytes
|
||||
## containing zero, so it is somewhat safer than ``createSharedU``.
|
||||
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.}
|
||||
## 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
|
||||
|
|
@ -1525,7 +1525,7 @@ const
|
|||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
## is the version of Nim as a string.
|
||||
|
||||
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
||||
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
||||
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
|
||||
|
||||
# GC interface:
|
||||
|
|
@ -1805,7 +1805,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
|
|||
return
|
||||
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
|
||||
## a fixed length array into a sequence as it always copies every element
|
||||
## of `a`.
|
||||
|
|
@ -1853,7 +1853,7 @@ when not defined(NimrodVM):
|
|||
else:
|
||||
proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
|
||||
asm """return `x`"""
|
||||
|
||||
|
||||
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
||||
## Generic equals operator for sequences: relies on a equals operator for
|
||||
## the element type `T`.
|
||||
|
|
@ -1879,7 +1879,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
|
|||
## for ``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
|
||||
## `s` as a stack and implements the common *pop* operation.
|
||||
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] {.
|
||||
magic: "Fields", noSideEffect.}
|
||||
## 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
|
||||
## in the loop body.
|
||||
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] {.
|
||||
magic: "FieldPairs", noSideEffect.}
|
||||
## 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
|
||||
## 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
|
||||
## of `x` and `y`.
|
||||
for a, b in fields(x, y):
|
||||
if a != b: return false
|
||||
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
|
||||
## of `x` and `y`. This implementation uses `cmp`.
|
||||
for a, b in fields(x, y):
|
||||
|
|
@ -2002,7 +2002,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
|
|||
if c > 0: return false
|
||||
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
|
||||
## of `x` and `y`. This implementation uses `cmp`.
|
||||
for a, b in fields(x, y):
|
||||
|
|
@ -2011,7 +2011,7 @@ proc `<`*[T: tuple](x, y: T): bool =
|
|||
if c > 0: 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
|
||||
## of `x`. Example:
|
||||
##
|
||||
|
|
@ -2021,13 +2021,13 @@ proc `$`*[T: tuple|object](x: T): string =
|
|||
result = "("
|
||||
var firstElement = true
|
||||
for name, value in fieldPairs(x):
|
||||
if not(firstElement): result.add(", ")
|
||||
if not firstElement: result.add(", ")
|
||||
result.add(name)
|
||||
result.add(": ")
|
||||
result.add($value)
|
||||
firstElement = false
|
||||
result.add(")")
|
||||
|
||||
|
||||
proc collectionToString[T](x: T, b, e: string): string =
|
||||
result = b
|
||||
var firstElement = true
|
||||
|
|
@ -2037,7 +2037,7 @@ proc collectionToString[T](x: T, b, e: string): string =
|
|||
firstElement = false
|
||||
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
|
||||
## of `x`. Example:
|
||||
##
|
||||
|
|
@ -2045,7 +2045,7 @@ proc `$`*[T](x: set[T]): string =
|
|||
## ${23, 45} == "{23, 45}"
|
||||
collectionToString(x, "{", "}")
|
||||
|
||||
proc `$`*[T](x: seq[T]): string =
|
||||
proc `$`*[T](x: seq[T]): string =
|
||||
## generic ``$`` operator for seqs that is lifted from the components
|
||||
## of `x`. Example:
|
||||
##
|
||||
|
|
@ -2056,7 +2056,7 @@ proc `$`*[T](x: seq[T]): string =
|
|||
when false:
|
||||
# causes bootstrapping to fail as we use array of chars and cstring should
|
||||
# match better ...
|
||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||
collectionToString(x, "[", "]")
|
||||
|
||||
# ----------------- GC interface ---------------------------------------------
|
||||
|
|
@ -2098,14 +2098,14 @@ when not defined(nimrodVM) and hostOS != "standalone":
|
|||
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||
## returns an informative string about the GC's activity. This may be useful
|
||||
## for tweaking.
|
||||
|
||||
|
||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||
proc GC_ref*[T](x: seq[T]) {.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
|
||||
## 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: seq[T]) {.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
|
||||
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
||||
## is caught and does not propagate further through the call stack.
|
||||
|
||||
|
||||
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
|
||||
## writes an error message and terminates the program. `outOfMemHook` can
|
||||
## be used to raise an exception in case of OOM like so:
|
||||
##
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## var gOutOfMem: ref EOutOfMemory
|
||||
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
||||
## gOutOfMem.msg = "out of memory"
|
||||
##
|
||||
##
|
||||
## proc handleOOM() =
|
||||
## raise gOutOfMem
|
||||
##
|
||||
|
|
@ -2210,7 +2210,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
|
|||
## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
|
||||
## instead.
|
||||
|
||||
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
||||
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
||||
tags: [], raises: [].}
|
||||
## 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
|
||||
|
|
@ -2262,7 +2262,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
|
|||
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
|
||||
if x < 0: -x else: x
|
||||
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
|
||||
## checking is turned on).
|
||||
if x < 0: -x else: x
|
||||
|
|
@ -2318,14 +2318,14 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
# we use binary mode in Windows:
|
||||
setmode(fileno(c_stdin), O_BINARY)
|
||||
setmode(fileno(c_stdout), O_BINARY)
|
||||
|
||||
|
||||
when defined(endb):
|
||||
proc endbStep()
|
||||
|
||||
# ----------------- IO Part ------------------------------------------------
|
||||
when hostOS != "standalone":
|
||||
type
|
||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||
final, incompletestruct.} = object
|
||||
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`.
|
||||
##
|
||||
## Default mode is readonly. Returns true iff the file could be opened.
|
||||
|
||||
|
||||
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`.
|
||||
##
|
||||
## 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 {.
|
||||
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`
|
||||
## file variables.
|
||||
##
|
||||
|
|
@ -2398,7 +2398,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
|
||||
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
||||
## Returns true iff `f` is at the end.
|
||||
|
||||
|
||||
proc readChar*(f: File): char {.
|
||||
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||
## 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
|
||||
## current file position is not at the beginning of the file.
|
||||
|
||||
|
||||
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
||||
## 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.
|
||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||
## ``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.}
|
||||
## reads a line of text from the file `f` into `line`. `line` must not be
|
||||
## ``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``
|
||||
## 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.}
|
||||
## writes the values `x` to `f` and then writes "\n".
|
||||
## May throw an IO exception.
|
||||
|
|
@ -2544,11 +2544,11 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
dealloc(a)
|
||||
|
||||
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.}
|
||||
## 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.}
|
||||
## 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
|
||||
hasRaiseAction: bool
|
||||
raiseAction: proc (e: ref Exception): bool {.closure.}
|
||||
|
||||
|
||||
when declared(initAllocator):
|
||||
initAllocator()
|
||||
when hasThreadSupport:
|
||||
|
|
@ -2576,7 +2576,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
||||
## allows you to override the behaviour of your application when CTRL+C
|
||||
## is pressed. Only one such hook is supported.
|
||||
|
||||
|
||||
proc writeStackTrace*() {.tags: [WriteIOEffect].}
|
||||
## writes the current stack trace to ``stderr``. This is only works
|
||||
## for debug builds.
|
||||
|
|
@ -2587,20 +2587,20 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
proc getStackTrace*(e: ref Exception): string
|
||||
## gets the stack trace associated with `e`, which is the stack that
|
||||
## lead to the ``raise`` statement. This only works for debug builds.
|
||||
|
||||
|
||||
{.push stack_trace: off, profiler:off.}
|
||||
when hostOS == "standalone":
|
||||
include "system/embedded"
|
||||
else:
|
||||
include "system/excpt"
|
||||
include "system/chcks"
|
||||
|
||||
|
||||
# we cannot compile this with stack tracing on
|
||||
# as it would recurse endlessly!
|
||||
include "system/arithm"
|
||||
{.pop.} # stack trace
|
||||
{.pop.} # stack trace
|
||||
|
||||
|
||||
when hostOS != "standalone" and not defined(NimrodVM):
|
||||
include "system/dyncalls"
|
||||
when not defined(NimrodVM):
|
||||
|
|
@ -2608,7 +2608,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
|
||||
const
|
||||
GenericSeqSize = (2 * sizeof(int))
|
||||
|
||||
|
||||
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
|
||||
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
||||
var d: int
|
||||
|
|
@ -2728,7 +2728,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
|||
## process(value)
|
||||
## else:
|
||||
## echo "Value too big!"
|
||||
|
||||
|
||||
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
||||
## 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!"
|
||||
## else:
|
||||
## process(value)
|
||||
|
||||
|
||||
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
||||
## retrieves the raw proc pointer of the closure `x`. This is
|
||||
## useful for interfacing closures with C.
|
||||
|
|
@ -2774,7 +2774,7 @@ elif defined(JS):
|
|||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
|
||||
proc getOccupiedMem(): int = return -1
|
||||
proc getFreeMem(): int = return -1
|
||||
proc getTotalMem(): int = return -1
|
||||
|
|
@ -2797,7 +2797,7 @@ elif defined(JS):
|
|||
if x == y: return 0
|
||||
if x < y: return -1
|
||||
return 1
|
||||
|
||||
|
||||
when defined(nimffi):
|
||||
include "system/sysio"
|
||||
|
||||
|
|
@ -2831,14 +2831,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
|
|||
# cut down:
|
||||
setLen(s, newLen)
|
||||
# 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":
|
||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||
## slice operation for strings. Negative indexes are supported.
|
||||
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
|
||||
## ``b.len`` is not exactly the number of elements that are referred to
|
||||
## 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
|
||||
newSeq(result, L)
|
||||
var j = x.a
|
||||
for i in 0.. <L:
|
||||
for i in 0.. <L:
|
||||
result[i] = a[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
|
||||
if L == b.len:
|
||||
var j = x.a
|
||||
for i in 0 .. <L:
|
||||
for i in 0 .. <L:
|
||||
a[j] = b[i]
|
||||
inc(j)
|
||||
else:
|
||||
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.
|
||||
var a = x.a-|s
|
||||
var L = x.b-|s - a + 1
|
||||
newSeq(result, L)
|
||||
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
|
||||
## ``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 L = x.b-|s - a + 1
|
||||
if L == b.len:
|
||||
|
|
@ -2937,7 +2937,7 @@ proc staticExec*(command: string, input = ""): string {.
|
|||
## to the executed program.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||
## "\nCompiled on " & staticExec("uname -v")
|
||||
##
|
||||
## `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.}
|
||||
## converts the AST of `x` into a string representation. This is very useful
|
||||
## for debugging.
|
||||
|
||||
|
||||
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
||||
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
||||
## 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
|
||||
## statements following `onFailedAssert` in the current lexical scope.
|
||||
## Can be defined multiple times in a single function.
|
||||
##
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## proc example(x: int): TErrorCode =
|
||||
## onFailedAssert(msg):
|
||||
## log msg
|
||||
## return E_FAIL
|
||||
##
|
||||
##
|
||||
## assert(...)
|
||||
##
|
||||
##
|
||||
## onFailedAssert(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.} =
|
||||
## 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.
|
||||
when not defined(JS) and not defined(NimrodVM):
|
||||
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.} =
|
||||
## 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.
|
||||
when not defined(JS) and not defined(NimrodVM):
|
||||
var s = cast[PGenericSeq](s)
|
||||
|
|
@ -3141,13 +3141,13 @@ else:
|
|||
when false:
|
||||
template eval*(blk: stmt): stmt =
|
||||
## 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
|
||||
macro payload: stmt {.gensym.} = blk
|
||||
payload()
|
||||
|
||||
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`.
|
||||
var xl = x.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.} =
|
||||
if src != nil:
|
||||
result = rawNewString(src.space)
|
||||
result = rawNewStringNoInit(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) =
|
||||
var
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -48,7 +48,7 @@ type
|
|||
TWalkOp = enum
|
||||
waMarkGlobal, # 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
|
||||
|
||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||
|
|
@ -61,9 +61,9 @@ type
|
|||
maxThreshold: int # max threshold that has been set
|
||||
maxStackSize: int # max stack size
|
||||
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
|
||||
|
||||
|
||||
TGcHeap {.final, pure.} = object # this contains the zero count and
|
||||
# non-zero count table
|
||||
stackBottom: pointer
|
||||
|
|
@ -88,11 +88,11 @@ var
|
|||
when not defined(useNimRtl):
|
||||
instantiateForRegion(gch.region)
|
||||
|
||||
template acquire(gch: TGcHeap) =
|
||||
template acquire(gch: TGcHeap) =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
acquireSys(HeapLock)
|
||||
|
||||
template release(gch: TGcHeap) =
|
||||
template release(gch: TGcHeap) =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
releaseSys(HeapLock)
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
|
|||
# convert pointer to userdata to object (=pointer to refcount)
|
||||
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
|
||||
|
||||
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): stmt = discard atomicInc(x, rcIncrement)
|
||||
else:
|
||||
template `--`(x: expr): expr =
|
||||
template `--`(x: expr): expr =
|
||||
dec(x, rcIncrement)
|
||||
x <% rcIncrement
|
||||
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
||||
|
|
@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
|
|||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||
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!
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
acquireSys(HeapLock)
|
||||
|
|
@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
|
|||
rtlAddCycleRoot(c)
|
||||
#writeCell("decRef", c)
|
||||
|
||||
proc incRef(c: PCell) {.inline.} =
|
||||
proc incRef(c: PCell) {.inline.} =
|
||||
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
||||
c.refcount = c.refcount +% rcIncrement
|
||||
# and not colorMask
|
||||
|
|
@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
|||
dest[] = src
|
||||
|
||||
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.
|
||||
if src != nil:
|
||||
var c = usrToCell(src)
|
||||
++c.refcount
|
||||
if dest[] != nil:
|
||||
if dest[] != nil:
|
||||
var c = usrToCell(dest[])
|
||||
if --c.refcount:
|
||||
rtlAddZCT(c)
|
||||
|
|
@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
|
|||
if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
|
||||
else:
|
||||
# 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")
|
||||
dest[] = src
|
||||
|
||||
|
|
@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc:
|
|||
echo "[GC] cannot register global variable; too many global variables"
|
||||
quit 1
|
||||
|
||||
proc cellsetReset(s: var TCellSet) =
|
||||
proc cellsetReset(s: var TCellSet) =
|
||||
deinit(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}:
|
||||
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
||||
else:
|
||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||
n.sons[i].typ, op)
|
||||
else:
|
||||
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.
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
# Slots to try cache hit
|
||||
# 1 32%
|
||||
# 4 59%
|
||||
|
|
@ -461,6 +461,9 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
|||
|
||||
{.pop.}
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
|
|
@ -481,7 +484,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
|||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||
collectCT(gch)
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
||||
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).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
|
||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||
acquire(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 elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
copyMem(res, ol, 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)
|
||||
gcTrace(ol, csZctFreed)
|
||||
gcTrace(res, csAllocated)
|
||||
when reallyDealloc:
|
||||
when reallyDealloc:
|
||||
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
||||
if ol.refcount shr rcShift <=% 1:
|
||||
# free immediately to save space:
|
||||
|
|
@ -580,7 +583,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
|||
prepareDealloc(c)
|
||||
gcTrace(c, csCycFreed)
|
||||
when logGC: writeCell("cycle collector dealloc cell", c)
|
||||
when reallyDealloc:
|
||||
when reallyDealloc:
|
||||
sysAssert(allocInv(gch.region), "free cyclic cell")
|
||||
rawDealloc(gch.region, c)
|
||||
else:
|
||||
|
|
@ -767,7 +770,7 @@ proc collectCycles(gch: var TGcHeap) =
|
|||
gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
|
||||
gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
|
||||
if canBeCycleRoot(c):
|
||||
#if c notin gch.cycleRoots:
|
||||
#if c notin gch.cycleRoots:
|
||||
inc cycleRootsLen
|
||||
incl(gch.cycleRoots, c)
|
||||
gcAssert c.typ != nil, "addBackStackRoots 2"
|
||||
|
|
@ -794,12 +797,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
|||
add(gch.decStack, cell)
|
||||
sysAssert(allocInv(gch.region), "gcMark end")
|
||||
|
||||
proc markThreadStacks(gch: var TGcHeap) =
|
||||
proc markThreadStacks(gch: var TGcHeap) =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
{.error: "not fully implemented".}
|
||||
var it = threadList
|
||||
while it != nil:
|
||||
# mark registers:
|
||||
# mark registers:
|
||||
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
||||
var sp = cast[TAddress](it.stackBottom)
|
||||
var max = cast[TAddress](it.stackTop)
|
||||
|
|
@ -933,7 +936,7 @@ else:
|
|||
while sp <=% max:
|
||||
gcMark(gch, cast[PPointer](sp)[])
|
||||
sp = sp +% sizeof(pointer)
|
||||
|
||||
|
||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||
forEachStackSlot(gch, gcMark)
|
||||
|
||||
|
|
@ -946,13 +949,13 @@ when useMarkForDebug or useBackupGc:
|
|||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc collectZCT(gch: var TGcHeap): bool =
|
||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||
# deep freeing, which is bad for incremental operation. In order to
|
||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||
# deep freeing, which is bad for incremental operation. In order to
|
||||
# avoid a deep stack, we move objects to keep the ZCT small.
|
||||
# This is performance critical!
|
||||
const workPackage = 100
|
||||
var L = addr(gch.zct.len)
|
||||
|
||||
|
||||
when withRealTime:
|
||||
var steps = workPackage
|
||||
var t0: TTicks
|
||||
|
|
@ -962,15 +965,15 @@ proc collectZCT(gch: var TGcHeap): bool =
|
|||
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
||||
# remove from ZCT:
|
||||
gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
|
||||
|
||||
|
||||
c.refcount = c.refcount and not ZctFlag
|
||||
gch.zct.d[0] = gch.zct.d[L[] - 1]
|
||||
dec(L[])
|
||||
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 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.
|
||||
# In any case, it should be removed from the ZCT. But not
|
||||
# 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():
|
||||
prepareDealloc(c)
|
||||
forAllChildren(c, waZctDecRef)
|
||||
when reallyDealloc:
|
||||
when reallyDealloc:
|
||||
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
||||
rawDealloc(gch.region, c)
|
||||
else:
|
||||
|
|
@ -994,7 +997,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
|||
steps = workPackage
|
||||
if gch.maxPause > 0:
|
||||
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
|
||||
# order to miss deadlines less often:
|
||||
if duration >= gch.maxPause - 50_000:
|
||||
|
|
@ -1017,7 +1020,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
|||
when withRealTime:
|
||||
let t0 = getticks()
|
||||
sysAssert(allocInv(gch.region), "collectCT: begin")
|
||||
|
||||
|
||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||
sysAssert(gch.decStack.len == 0, "collectCT")
|
||||
prepareForInteriorPointerChecking(gch.region)
|
||||
|
|
@ -1036,7 +1039,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
|||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||
unmarkStackAndRegisters(gch)
|
||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||
|
||||
|
||||
when withRealTime:
|
||||
let duration = getticks() - t0
|
||||
gch.stat.maxPause = max(gch.stat.maxPause, duration)
|
||||
|
|
@ -1050,8 +1053,12 @@ when useMarkForDebug or useBackupGc:
|
|||
markGlobals(gch)
|
||||
|
||||
proc collectCT(gch: var TGcHeap) =
|
||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||
# 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:
|
||||
when useMarkForDebug:
|
||||
prepareForInteriorPointerChecking(gch.region)
|
||||
|
|
@ -1070,7 +1077,7 @@ when withRealTime:
|
|||
acquire(gch)
|
||||
gch.maxPause = us.toNano
|
||||
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:
|
||||
collectCTBody(gch)
|
||||
release(gch)
|
||||
|
|
@ -1078,13 +1085,13 @@ when withRealTime:
|
|||
proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc GC_disable() =
|
||||
proc GC_disable() =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
discard atomicInc(gch.recGcLock, 1)
|
||||
else:
|
||||
inc(gch.recGcLock)
|
||||
proc GC_enable() =
|
||||
if gch.recGcLock > 0:
|
||||
if gch.recGcLock > 0:
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
discard atomicDec(gch.recGcLock, 1)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
|||
return
|
||||
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
|
||||
acquire(gch)
|
||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
# 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.
|
||||
{.push profiler:off.}
|
||||
|
||||
const
|
||||
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
|
||||
# bootstrapping and use more memory
|
||||
rcWhite = 0
|
||||
|
|
@ -29,21 +29,21 @@ type
|
|||
TWalkOp = enum
|
||||
waMarkGlobal, # we need to mark conservatively for global marker procs
|
||||
# as these may refer to a global var and not to a thread
|
||||
# local
|
||||
# local
|
||||
waMarkPrecise # fast precise marking
|
||||
|
||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||
# A ref type can have a finalizer that is called before the object's
|
||||
# storage is freed.
|
||||
|
||||
|
||||
TGlobalMarkerProc = proc () {.nimcall, benign.}
|
||||
|
||||
TGcStat = object
|
||||
collections: int # number of performed full collections
|
||||
maxThreshold: int # max threshold that has been set
|
||||
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
|
||||
# non-zero count table
|
||||
stackBottom: pointer
|
||||
|
|
@ -64,11 +64,11 @@ var
|
|||
when not defined(useNimRtl):
|
||||
instantiateForRegion(gch.region)
|
||||
|
||||
template acquire(gch: TGcHeap) =
|
||||
template acquire(gch: TGcHeap) =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
acquireSys(HeapLock)
|
||||
|
||||
template release(gch: TGcHeap) =
|
||||
template release(gch: TGcHeap) =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
releaseSys(HeapLock)
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ proc prepareDealloc(cell: PCell) =
|
|||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||
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:
|
||||
when false:
|
||||
when withBitvectors: excl(gch.allocated, usrToCell(p))
|
||||
|
|
@ -261,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
|||
zeroMem(result, 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.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
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)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
|
||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||
acquire(gch)
|
||||
collectCT(gch)
|
||||
var ol = usrToCell(old)
|
||||
sysAssert(ol.typ != nil, "growObj: 1")
|
||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
||||
var elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
copyMem(res, ol, 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))
|
||||
if objStart != nil:
|
||||
mark(gch, objStart)
|
||||
|
||||
|
||||
# ----------------- stack management --------------------------------------
|
||||
# inspired from Smart Eiffel
|
||||
|
||||
|
|
@ -536,7 +540,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
|||
markStackAndRegisters(gch)
|
||||
markGlobals(gch)
|
||||
sweep(gch)
|
||||
|
||||
|
||||
inc(gch.stat.collections)
|
||||
when withBitvectors:
|
||||
deinit(gch.marked)
|
||||
|
|
@ -544,19 +548,19 @@ proc collectCTBody(gch: var TGcHeap) =
|
|||
gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
|
||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||
|
||||
|
||||
proc collectCT(gch: var TGcHeap) =
|
||||
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
||||
collectCTBody(gch)
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc GC_disable() =
|
||||
proc GC_disable() =
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
atomicInc(gch.recGcLock, 1)
|
||||
else:
|
||||
inc(gch.recGcLock)
|
||||
proc GC_enable() =
|
||||
if gch.recGcLock > 0:
|
||||
if gch.recGcLock > 0:
|
||||
when hasThreadSupport and hasSharedHeap:
|
||||
atomicDec(gch.recGcLock, 1)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ when declared(NimString):
|
|||
# we are in system module:
|
||||
{.pragma: codegenType, compilerproc.}
|
||||
else:
|
||||
{.pragma: codegenType.}
|
||||
{.pragma: codegenType, importc.}
|
||||
|
||||
type
|
||||
# This should be he same as ast.TTypeKind
|
||||
|
|
@ -65,7 +65,7 @@ type
|
|||
tyBigNum,
|
||||
|
||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||
TNimNode {.codegenType, final.} = object
|
||||
TNimNode {.codegenType.} = object
|
||||
kind: TNimNodeKind
|
||||
offset: int
|
||||
typ: ptr TNimType
|
||||
|
|
@ -78,7 +78,7 @@ type
|
|||
ntfAcyclic = 1, # type cannot form a cycle
|
||||
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
||||
# version
|
||||
TNimType {.codegenType, final.} = object
|
||||
TNimType {.codegenType.} = object
|
||||
size: int
|
||||
kind: TNimKind
|
||||
flags: set[TNimTypeFlag]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -23,7 +23,7 @@ const
|
|||
leakDetector = false
|
||||
overwriteFree = false
|
||||
trackAllocationSource = leakDetector
|
||||
|
||||
|
||||
cycleGC = true # (de)activate the cycle GC
|
||||
reallyDealloc = true # for debugging purposes this can be set to false
|
||||
reallyOsDealloc = true
|
||||
|
|
@ -71,13 +71,13 @@ when defined(boehmgc):
|
|||
const boehmLib = "libgc.dylib"
|
||||
else:
|
||||
const boehmLib = "/usr/lib/libgc.so.1"
|
||||
|
||||
|
||||
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
|
||||
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
||||
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
||||
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
||||
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
||||
proc boehmGCincremental {.
|
||||
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
||||
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
||||
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
||||
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
||||
proc boehmAlloc(size: int): pointer {.
|
||||
importc: "GC_malloc", dynlib: boehmLib.}
|
||||
proc boehmAllocAtomic(size: int): pointer {.
|
||||
|
|
@ -85,7 +85,7 @@ when defined(boehmgc):
|
|||
proc boehmRealloc(p: pointer, size: int): pointer {.
|
||||
importc: "GC_realloc", dynlib: boehmLib.}
|
||||
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
|
||||
|
||||
|
||||
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
|
||||
## Return the number of bytes in the heap. Excludes collector private
|
||||
## data structures. Includes empty blocks and fragmentation loss.
|
||||
|
|
@ -108,7 +108,7 @@ when defined(boehmgc):
|
|||
zeroMem(result, size)
|
||||
|
||||
when not defined(useNimRtl):
|
||||
|
||||
|
||||
proc alloc(size: int): pointer =
|
||||
result = boehmAlloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
|
|
@ -119,7 +119,7 @@ when defined(boehmgc):
|
|||
result = boehmRealloc(p, newsize)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc dealloc(p: pointer) = boehmDealloc(p)
|
||||
|
||||
|
||||
proc allocShared(size: int): pointer =
|
||||
result = boehmAlloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
|
|
@ -148,14 +148,14 @@ when defined(boehmgc):
|
|||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
|
||||
proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
|
||||
proc getFreeMem(): int = return boehmGetFreeBytes()
|
||||
proc getTotalMem(): int = return boehmGetHeapSize()
|
||||
|
||||
proc setStackBottom(theStackBottom: pointer) = discard
|
||||
|
||||
proc initGC() =
|
||||
proc initGC() =
|
||||
when defined(macosx): boehmGCinit()
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
|
|
@ -171,7 +171,7 @@ when defined(boehmgc):
|
|||
|
||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||
|
||||
|
||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
|
|
@ -181,20 +181,20 @@ when defined(boehmgc):
|
|||
|
||||
type
|
||||
TMemRegion = object {.final, pure.}
|
||||
|
||||
|
||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
||||
result = boehmAlloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
||||
result = alloc(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() {.inline.} = discard
|
||||
|
||||
include "system/cellsets"
|
||||
elif defined(nogc) and defined(useMalloc):
|
||||
|
||||
|
||||
when not defined(useNimRtl):
|
||||
proc alloc(size: int): pointer =
|
||||
result = cmalloc(size)
|
||||
|
|
@ -206,7 +206,7 @@ elif defined(nogc) and defined(useMalloc):
|
|||
result = crealloc(p, newsize)
|
||||
if result == nil: raiseOutOfMem()
|
||||
proc dealloc(p: pointer) = cfree(p)
|
||||
|
||||
|
||||
proc allocShared(size: int): pointer =
|
||||
result = cmalloc(size)
|
||||
if result == nil: raiseOutOfMem()
|
||||
|
|
@ -225,11 +225,11 @@ elif defined(nogc) and defined(useMalloc):
|
|||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
|
||||
proc getOccupiedMem(): int = discard
|
||||
proc getFreeMem(): int = discard
|
||||
proc getTotalMem(): int = discard
|
||||
|
||||
|
||||
proc setStackBottom(theStackBottom: pointer) = discard
|
||||
|
||||
proc initGC() = discard
|
||||
|
|
@ -240,13 +240,15 @@ elif defined(nogc) and defined(useMalloc):
|
|||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
result = alloc(size)
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer =
|
||||
result = realloc(old, newsize)
|
||||
|
||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||
|
||||
|
||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
|
|
@ -256,7 +258,7 @@ elif defined(nogc) and defined(useMalloc):
|
|||
|
||||
type
|
||||
TMemRegion = object {.final, pure.}
|
||||
|
||||
|
||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
||||
result = alloc(size)
|
||||
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
|
||||
# possible implementation has to have a way to determine the object's size.
|
||||
# C just sucks.
|
||||
when appType == "lib":
|
||||
when appType == "lib":
|
||||
{.warning: "nogc in a library context may not work".}
|
||||
|
||||
|
||||
include "system/alloc"
|
||||
|
||||
proc initGC() = discard
|
||||
|
|
@ -285,10 +287,14 @@ elif defined(nogc):
|
|||
proc GC_enableMarkAndSweep() = discard
|
||||
proc GC_disableMarkAndSweep() = discard
|
||||
proc GC_getStatistics(): string = return ""
|
||||
|
||||
|
||||
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
result = alloc0(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
result = alloc(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
cast[PGenericSeq](result).len = len
|
||||
|
|
@ -299,7 +305,7 @@ elif defined(nogc):
|
|||
proc setStackBottom(theStackBottom: pointer) = discard
|
||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||
|
||||
|
||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
dest[] = src
|
||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
|
|
@ -327,6 +333,6 @@ else:
|
|||
include "system/gc"
|
||||
else:
|
||||
include "system/gc"
|
||||
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ proc readAllFile(file: File): string =
|
|||
proc readAll(file: File): TaintedString =
|
||||
# Separate handling needed because we need to buffer when we
|
||||
# don't know the overall length of the File.
|
||||
var len = rawFileSize(file)
|
||||
if len >= 0:
|
||||
let len = if file != stdin: rawFileSize(file) else: -1
|
||||
if len > 0:
|
||||
result = readAllFile(file, len).TaintedString
|
||||
else:
|
||||
result = readAllBuffer(file).TaintedString
|
||||
|
|
|
|||
|
|
@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
|||
if a == b: return true
|
||||
if a == nil or b == nil: return false
|
||||
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):
|
||||
template allocStr(size: expr): expr =
|
||||
cast[NimString](allocAtomic(size))
|
||||
|
||||
template allocStrNoInit(size: expr): expr =
|
||||
cast[NimString](boehmAllocAtomic(size))
|
||||
else:
|
||||
template allocStr(size: expr): expr =
|
||||
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.} =
|
||||
var s = space
|
||||
if s < 8: s = 7
|
||||
if s < 7: s = 7
|
||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
|
||||
|
|
@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
|||
var start = max(start, 0)
|
||||
var len = min(last, s.len-1) - start + 1
|
||||
if len > 0:
|
||||
result = rawNewString(len)
|
||||
result = rawNewStringNoInit(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
|
||||
#result.data[len] = '\0'
|
||||
c_memcpy(result.data, addr(s.data[start]), len)
|
||||
result.data[len] = '\0'
|
||||
else:
|
||||
result = rawNewString(len)
|
||||
|
||||
|
|
@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
|||
result = copyStrLast(s, start, s.len-1)
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
||||
result = rawNewString(len)
|
||||
result = rawNewStringNoInit(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, str, (len+1) * sizeof(char))
|
||||
#result.data[len] = '\0' # readline relies on this!
|
||||
c_memcpy(result.data, str, len + 1)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||
result = toNimStr(str, c_strlen(str))
|
||||
|
|
@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
|
|||
if (src.reserved and seqShallowFlag) != 0:
|
||||
result = src
|
||||
else:
|
||||
result = rawNewString(src.space)
|
||||
result = rawNewStringNoInit(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.} =
|
||||
if src != nil:
|
||||
var s = src.space
|
||||
if s < 8: s = 7
|
||||
when declared(newObjRC1):
|
||||
var s = src.len
|
||||
if s < 7: s = 7
|
||||
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
||||
s+1))
|
||||
result.reserved = s
|
||||
else:
|
||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
|
||||
proc hashString(s: string): int {.compilerproc.} =
|
||||
# the compiler needs exactly the same hash function!
|
||||
# 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:
|
||||
result.reserved = resize(result.space)
|
||||
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+1] = '\0'
|
||||
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.reserved = 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
|
||||
|
||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||
|
|
@ -203,7 +215,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
|||
GenericSeqSize))
|
||||
elif newLen < result.len:
|
||||
# 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):
|
||||
when compileOption("gc", "v2"):
|
||||
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) +%
|
||||
GenericSeqSize +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
|
||||
# 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).
|
||||
# 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] == ',':
|
||||
buf[i] = '.'
|
||||
hasDot = true
|
||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||
hasDot = true
|
||||
if not hasDot:
|
||||
buf[n] = '.'
|
||||
buf[n+1] = '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,
|
||||
header: "<stdlib.h>", noSideEffect.}
|
||||
|
|
@ -299,7 +321,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
|||
template addToBuf(c) =
|
||||
if ti < t.high:
|
||||
t[ti] = c; inc(ti)
|
||||
|
||||
|
||||
# Sign?
|
||||
if s[i] == '+' or 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+1] == 'N' or s[i+1] == 'n':
|
||||
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
|
||||
return i+3 - start
|
||||
return 0
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ when useWinVersion:
|
|||
from winlean import SocketHandle
|
||||
else:
|
||||
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):
|
||||
const
|
||||
DLLSSLName = "libssl" & versions & ".dylib"
|
||||
|
|
@ -141,6 +141,14 @@ const
|
|||
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
|
||||
# * 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
|
||||
# * (buffer contents must stay the same!); this is not the default to avoid
|
||||
# * 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{.
|
||||
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 =
|
||||
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 bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
||||
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
||||
|
|
@ -341,8 +381,6 @@ else:
|
|||
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{.
|
||||
cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
|
|
|
|||
21
readme.md
21
readme.md
|
|
@ -1,5 +1,5 @@
|
|||
# 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.
|
||||
|
||||
## 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
|
||||
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
|
||||
[Nimbuild](http://build.nim-lang.org/). Your platform however may not
|
||||
currently be built for.
|
||||
|
||||
The compiler currently supports the following platform and architecture
|
||||
The compiler currently supports the following platform and architecture
|
||||
combinations:
|
||||
|
||||
|
||||
* Windows (Windows XP or greater) - x86 and x86_64
|
||||
* Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
|
||||
* 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.
|
||||
|
||||
To build from source you will need:
|
||||
|
|
@ -39,8 +35,7 @@ $ bin/nim c koch
|
|||
$ ./koch boot -d:release
|
||||
```
|
||||
|
||||
``koch install [dir]`` may then be used to install Nim, or you can simply
|
||||
add it to your PATH. More ``koch`` related options are documented in
|
||||
``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
|
||||
[doc/koch.txt](doc/koch.txt).
|
||||
|
||||
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).
|
||||
|
||||
## License
|
||||
The compiler and the standard library are licensed under the MIT license,
|
||||
except for some modules where the documentation suggests otherwise. This means
|
||||
that you can use any license for your own programs developed with Nim,
|
||||
The compiler and the standard library are licensed under the MIT license,
|
||||
except for some modules where the documentation suggests otherwise. This means
|
||||
that you can use any license for your own programs developed with Nim,
|
||||
allowing you to create commercial applications.
|
||||
|
||||
Read copying.txt for more details.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
discard """
|
||||
line: 21
|
||||
errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'"
|
||||
output: "action 3 arg"
|
||||
"""
|
||||
|
||||
import tables
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ discard """
|
|||
WARNING: false first assertion from bar
|
||||
ERROR: false second assertion from bar
|
||||
-1
|
||||
tests/assert/tfailedassert.nim:27 false assertion from foo
|
||||
tfailedassert.nim:27 false assertion from foo
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
TLineInfo = tuple[filename: string, line: int]
|
||||
|
||||
TMyError = object of E_Base
|
||||
TMyError = object of Exception
|
||||
lineinfo: TLineInfo
|
||||
|
||||
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 """
|
||||
cmd: "nim cpp $target"
|
||||
cmd: "nim cpp $file"
|
||||
"""
|
||||
|
||||
import rawsockets
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
discard """
|
||||
cmd: "nim cpp $target"
|
||||
cmd: "nim cpp $file"
|
||||
"""
|
||||
|
||||
import typeinfo
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
discard """
|
||||
line: 9
|
||||
errormsg: "'a' is deprecated [Deprecated]"
|
||||
nimout: "a is deprecated [Deprecated]"
|
||||
"""
|
||||
|
||||
var
|
||||
a {.deprecated.}: array[0..11, int]
|
||||
|
||||
|
||||
a[8] = 1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
line: 20
|
||||
errormsg: " usage of a type with a destructor in a non destructible context"
|
||||
line: 23
|
||||
nimout: " usage of a type with a destructor in a non destructible context"
|
||||
"""
|
||||
|
||||
{.experimental.}
|
||||
|
|
@ -19,5 +19,9 @@ proc open: TMyObj =
|
|||
|
||||
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 """
|
||||
line: 7
|
||||
errormsg: "expression 'items' cannot be called"
|
||||
errormsg: "undeclared identifier: 'items'"
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
proc doTrace(n: PNode[T,D], level: int) =
|
||||
var space = repeatChar(2 * level)
|
||||
var space = spaces(2 * level)
|
||||
traceln(space)
|
||||
write stdout, "node: "
|
||||
if n == nil:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
# Bug #2022
|
||||
|
||||
discard """
|
||||
output: '''@[97, 45]
|
||||
@[true, false]
|
||||
@[false, false]'''
|
||||
"""
|
||||
|
||||
## 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
|
||||
## because it's more efficient than using procedure pointers and less
|
||||
|
|
@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
|
|||
input: Input
|
||||
|
||||
macro map(input, predicate: expr): expr =
|
||||
let predicate = callsite()[2]
|
||||
newNimNode(nnkObjConstr).add(
|
||||
newNimNode(nnkBracketExpr).add(
|
||||
ident"Mapped",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
file: "toop1.nim"
|
||||
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
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] = @[],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import streams
|
||||
from strutils import repeatChar
|
||||
from strutils import repeat
|
||||
|
||||
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
||||
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') =
|
||||
if str.len < length:
|
||||
s.write(str)
|
||||
s.write(repeatChar(length - str.len, padChar))
|
||||
s.write(repeat(padChar, length - str.len))
|
||||
elif str.len > length:
|
||||
s.write(str.substr(0, length - 1))
|
||||
else:
|
||||
|
|
@ -37,7 +37,7 @@ when isMainModule:
|
|||
testStream.setPosition 0
|
||||
testStream.writePaddedStr("Sup", 10)
|
||||
echo(repr(testStream), testStream.data.len)
|
||||
doAssert testStream.data == "Sup"&repeatChar(7, '\0')
|
||||
doAssert testStream.data == "Sup"&repeat('\0', 7)
|
||||
|
||||
testStream.setPosition 0
|
||||
res = testStream.readPaddedStr(10)
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ when isMainModule:
|
|||
discard """block:
|
||||
var
|
||||
TestFile: FileChallengePair
|
||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
||||
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||
testFile.file = checksumStr(contents)
|
||||
myAssets.add testFile"""
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ when defined(recordMode):
|
|||
isRecording = false
|
||||
proc zeroPad*(s: string; minLen: int): string =
|
||||
if s.len < minLen:
|
||||
result = repeatChar(minLen - s.len, '0')
|
||||
result = repeat(0, minLen - s.len)
|
||||
result.add s
|
||||
else:
|
||||
result = s
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ when isMainModule:
|
|||
var res = t.map(proc(z: int): int = result = z * 10)
|
||||
dumpSeq res
|
||||
|
||||
from strutils import toHex, repeatStr
|
||||
from strutils import toHex
|
||||
var foocakes = t.map(proc(z: int): string =
|
||||
result = toHex((z * 23).biggestInt, 4))
|
||||
result = toHex((z * 23).BiggestInt, 4))
|
||||
dumpSeq foocakes
|
||||
|
||||
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