diff options
115 files changed, 2571 insertions, 1693 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 6afc1db26..36e86a6f1 100644 --- a/compiler/ast.nim +++ b/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,7 +457,7 @@ type tfIterator, # type is really an iterator, not a tyProc tfShared, # type is 'shared' tfNotNil, # type cannot be 'nil' - + tfNeedsInit, # type constains a "not nil" constraint somewhere or some # other type so that it requires inititalization tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode @@ -520,7 +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) @@ -1327,11 +1325,11 @@ proc propagateToOwner*(owner, elem: PType) = owner.flags.incl tfNotNil elif owner.kind notin HaveTheirOwnEmpty: owner.flags.incl tfNeedsInit - + if tfNeedsInit in elem.flags: if owner.kind in HaveTheirOwnEmpty: discard else: owner.flags.incl tfNeedsInit - + if elem.isMetaType: owner.flags.incl tfHasMeta @@ -1348,15 +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 diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index e9b82d74b..c53e53b88 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -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() @@ -387,6 +387,9 @@ proc debugType(n: PType, maxRecDepth=100): PRope = if n.sym != nil: app(result, " ") app(result, n.sym.name.s) + if n.kind in IntegralTypes and n.n != nil: + app(result, ", node: ") + app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0: app(result, "(") for i in countup(0, sonsLen(n) - 1): @@ -405,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: @@ -437,29 +440,29 @@ 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: - writeln(stdout, "null") + msgWriteln("null") elif n.kind == skUnknown: - writeln(stdout, "skUnknown") + msgWriteln("skUnknown") else: #writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) - writeln(stdout, "$1_$2: $3, $4, $5, $6" % [ + msgWriteln("$1_$2: $3, $4, $5, $6" % [ n.name.s, $n.id, flagsToStr(n.flags).ropeToStr, flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr, $n.kind]) proc debug(n: PType) = - writeln(stdout, ropeToStr(debugType(n))) + msgWriteln(ropeToStr(debugType(n))) proc debug(n: PNode) = - writeln(stdout, ropeToStr(debugTree(n, 0, 100))) + msgWriteln(ropeToStr(debugTree(n, 0, 100))) const EmptySeq = @[] @@ -678,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 diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 3bc0d8afb..564d1fd36 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 0220d2066..9a5a3ab34 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -226,71 +226,8 @@ proc fillResult(param: PSym) = incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown -proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope = - when false: - if t.Kind in {tyRef, tyPtr, tyVar}: - var b = skipTypes(t.lastson, typedescInst) - if b.kind == tySet and mapSetType(b) == ctArray: - return getTypeDescAux(m, b, check) - result = getTypeDescAux(m, t, check) - -proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}: - result = OnStack - else: - result = OnUnknown - -proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, - check: var IntSet, declareEnvironment=true) = - params = nil - if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): - rettype = ~"void" - else: - rettype = getTypeDescAux(m, t.sons[0], check) - for i in countup(1, sonsLen(t.n) - 1): - if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") - var param = t.n.sons[i].sym - if isCompileTimeOnly(param.typ): continue - if params != nil: app(params, ~", ") - fillLoc(param.loc, locParam, param.typ, mangleName(param), - param.paramStorageLoc) - app(params, getParamTypeDesc(m, param.typ, check)) - if ccgIntroducedPtr(param): - app(params, ~"*") - incl(param.loc.flags, lfIndirect) - param.loc.s = OnUnknown - app(params, ~" ") - app(params, param.loc.r) - # declare the len field for open arrays: - var arr = param.typ - if arr.kind == tyVar: arr = arr.sons[0] - var j = 0 - while arr.kind in {tyOpenArray, tyVarargs}: - # this fixes the 'sort' bug: - if param.typ.kind == tyVar: param.loc.s = OnUnknown - # need to pass hidden parameter: - appf(params, ", NI $1Len$2", [param.loc.r, j.toRope]) - inc(j) - arr = arr.sons[0] - if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): - var arr = t.sons[0] - if params != nil: app(params, ", ") - app(params, getTypeDescAux(m, arr, check)) - if (mapReturnType(t.sons[0]) != ctArray): - app(params, "*") - appf(params, " Result", []) - if t.callConv == ccClosure and declareEnvironment: - if params != nil: app(params, ", ") - app(params, "void* ClEnv") - if tfVarargs in t.flags: - if params != nil: app(params, ", ") - app(params, "...") - if params == nil: app(params, "void)") - else: app(params, ")") - params = con("(", params) - proc typeNameOrLiteral(t: PType, literal: string): PRope = - if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): + if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: result = getTypeName(t) else: result = toRope(literal) @@ -327,7 +264,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope = result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) else: result = nil - + +proc pushType(m: BModule, typ: PType) = + add(m.typeStack, typ) + proc getTypePre(m: BModule, typ: PType): PRope = if typ == nil: result = toRope("void") else: @@ -354,6 +294,81 @@ proc getTypeForward(m: BModule, typ: PType): PRope = [structOrUnion(typ), result]) idTablePut(m.forwTypeCache, typ, result) else: internalError("getTypeForward(" & $typ.kind & ')') + +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope = + ## like getTypeDescAux but creates only a *weak* dependency. In other words + ## we know we only need a pointer to it so we only generate a struct forward + ## declaration: + var etB = t.skipTypes(abstractInst) + case etB.kind + of tyObject, tyTuple: + if isImportedCppType(etB) and t.kind == tyGenericInst: + result = getTypeDescAux(m, t, check) + else: + let x = getUniqueType(etB) + result = getTypeForward(m, x) + pushType(m, x) + else: + result = getTypeDescAux(m, t, check) + +proc paramStorageLoc(param: PSym): TStorageLoc = + if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}: + result = OnStack + else: + result = OnUnknown + +proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, + check: var IntSet, declareEnvironment=true) = + params = nil + if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): + rettype = ~"void" + else: + rettype = getTypeDescAux(m, t.sons[0], check) + for i in countup(1, sonsLen(t.n) - 1): + if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") + var param = t.n.sons[i].sym + if isCompileTimeOnly(param.typ): continue + if params != nil: app(params, ~", ") + fillLoc(param.loc, locParam, param.typ, mangleName(param), + param.paramStorageLoc) + if ccgIntroducedPtr(param): + app(params, getTypeDescWeak(m, param.typ, check)) + app(params, ~"*") + incl(param.loc.flags, lfIndirect) + param.loc.s = OnUnknown + else: + app(params, getTypeDescAux(m, param.typ, check)) + app(params, ~" ") + app(params, param.loc.r) + # declare the len field for open arrays: + var arr = param.typ + if arr.kind == tyVar: arr = arr.sons[0] + var j = 0 + while arr.kind in {tyOpenArray, tyVarargs}: + # this fixes the 'sort' bug: + if param.typ.kind == tyVar: param.loc.s = OnUnknown + # need to pass hidden parameter: + appf(params, ", NI $1Len$2", [param.loc.r, j.toRope]) + inc(j) + arr = arr.sons[0] + if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): + var arr = t.sons[0] + if params != nil: app(params, ", ") + if (mapReturnType(t.sons[0]) != ctArray): + app(params, getTypeDescWeak(m, arr, check)) + app(params, "*") + else: + app(params, getTypeDescAux(m, arr, check)) + appf(params, " Result", []) + if t.callConv == ccClosure and declareEnvironment: + if params != nil: app(params, ", ") + app(params, "void* ClEnv") + if tfVarargs in t.flags: + if params != nil: app(params, ", ") + app(params, "...") + if params == nil: app(params, "void)") + else: app(params, ")") + params = con("(", params) proc mangleRecFieldName(field: PSym, rectype: PType): PRope = if (rectype.sym != nil) and @@ -473,9 +488,6 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope, else: app(result, desc) app(result, "};" & tnl) -proc pushType(m: BModule, typ: PType) = - add(m.typeStack, typ) - proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # returns only the type's name var t = getUniqueType(typ) diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 134619d4a..25c1a12e5 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -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]) diff --git a/compiler/commands.nim b/compiler/commands.nim index c52515c76..a2d02e469 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -326,7 +326,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "link": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: addFileToLink(arg) - of "debuginfo": + of "debuginfo": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optCDebug) of "embedsrc": @@ -374,10 +374,20 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) - of "debugger": - processOnOffSwitch({optEndb}, arg, pass, info) - if optEndb in gOptions: defineSymbol("endb") - else: undefSymbol("endb") + of "debugger": + case arg.normalize + of "on", "endb": + gOptions.incl optEndb + defineSymbol("endb") + of "off": + gOptions.excl optEndb + undefSymbol("endb") + of "native", "gdb": + incl(gGlobalOptions, optCDebug) + gOptions = gOptions + {optLineDir} - {optEndb} + undefSymbol("endb") + else: + localError(info, "expected endb|gdb but found " & arg) of "profiler": processOnOffSwitch({optProfiler}, arg, pass, info) if optProfiler in gOptions: defineSymbol("profiler") diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index b98679ac6..b1a23802d 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -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 diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 29657a2ae..8959aa4df 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -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) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 5f6033e57..8888632b9 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -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 diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 7b975dbaa..5d1f73be4 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -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) diff --git a/compiler/importer.nim b/compiler/importer.nim index fbf3be4f2..57a1e542b 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -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 diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 34f842d4a..87847204f 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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") diff --git a/compiler/lexer.nim b/compiler/lexer.nim index fc40192b8..c86762121 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -181,10 +181,8 @@ proc prettyTok*(tok: TToken): string = else: result = tokToStr(tok) proc printTok*(tok: TToken) = - write(stdout, tok.line, ":", tok.col, "\t") - write(stdout, TokTypeToStr[tok.tokType]) - write(stdout, " ") - writeln(stdout, tokToStr(tok)) + msgWriteln($tok.line & ":" & $tok.col & "\t" & + TokTypeToStr[tok.tokType] & " " & tokToStr(tok)) var dummyIdent: PIdent diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 69475965d..18ca4aec7 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -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 diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 21d07f280..6d3379bb9 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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) diff --git a/compiler/main.nim b/compiler/main.nim index 42a782c02..f7592a891 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -62,7 +62,7 @@ proc commandCompileToC = compileProject() cgenWriteModules() if gCmd != cmdRun: - extccomp.callCCompiler(changeFileExt(gProjectFull, "")) + extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, "")) if isServing: # caas will keep track only of the compilation commands diff --git a/compiler/modules.nim b/compiler/modules.nim index db05ccc6c..a2b739efc 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -116,7 +116,7 @@ proc newModule(fileIdx: int32): PSym = result.kind = skModule let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) - if not isNimIdentifier(result.name.s): + if result.name.s != "-" and not isNimIdentifier(result.name.s): rawMessage(errInvalidModuleName, result.name.s) result.info = newLineInfo(fileIdx, 1, 1) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index ed28fea69..e15cdc86d 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -330,7 +330,7 @@ const errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & "because the parameter '$1' has a generic type", - errDestructorNotGenericEnough: "Destructor signarue is too specific. " & + errDestructorNotGenericEnough: "Destructor signature is too specific. " & "A destructor must be associated will all instantiations of a generic type", errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & "templates, macros and other inline iterators", @@ -443,7 +443,7 @@ type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKinds* = set[TNoteKind] - TFileInfo*{.final.} = object + TFileInfo* = object fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root shortName*: string # short name of the module @@ -458,7 +458,7 @@ type # and parsed; usually 'nil' but is used # for 'nimsuggest' - TLineInfo*{.final.} = object # This is designed to be as small as possible, + TLineInfo* = object # This is designed to be as small as possible, # because it is used # in syntax nodes. We save space here by using # two int16 and an int32. @@ -493,7 +493,7 @@ proc toCChar*(c: char): string = proc makeCString*(s: string): PRope = # BUGFIX: We have to split long strings into many ropes. Otherwise - # this could trigger an InternalError(). See the ropes module for + # this could trigger an internalError(). See the ropes module for # further information. const MaxLineLength = 64 @@ -696,7 +696,9 @@ proc msgWriteln*(s: string) = #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - if optStdout in gGlobalOptions: + if not isNil(writelnHook): + writelnHook(s) + elif optStdout in gGlobalOptions: if eStdErr in errorOutputs: writeln(stderr, s) else: if eStdOut in errorOutputs: writeln(stdout, s) @@ -720,7 +722,7 @@ type proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = template quit = if defined(debug) or gVerbosity >= 3 or msg == errInternal: - if stackTraceAvailable(): + if stackTraceAvailable() and isNil(writelnHook): writeStackTrace() else: msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") @@ -782,7 +784,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 diff --git a/compiler/nim.nim b/compiler/nim.nim index 215f1986e..b8ba2c6da 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -61,6 +61,8 @@ proc handleCmdLine() = if gCmd == cmdRun: tccgen.run(commands.arguments) if optRun in gGlobalOptions: + if gProjectName == "-": + gProjectFull = "stdinfile" if gCmd == cmdCompileToJS: var ex: string if options.outFile.len > 0: diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index e18e1c22a..f5db5ca4f 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -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") diff --git a/compiler/options.nim b/compiler/options.nim index d6d9389f5..1b4a624ab 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -283,19 +283,19 @@ when noTimeMachine: var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir]) discard p.waitForExit p.close - except E_Base, EOS: + except Exception: discard -proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = +proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = var (head, tail) = splitPath(f) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) var subdir = getGeneratedPath() # / head if createSubDir: - try: + try: createDir(subdir) when noTimeMachine: excludeDirFromTimeMachine(subdir) - except OSError: + except OSError: writeln(stdout, "cannot create directory: " & subdir) quit(1) result = joinPath(subdir, tail) diff --git a/compiler/parser.nim b/compiler/parser.nim index 8fbf033d8..9e4d45cd2 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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) ')' diff --git a/compiler/passes.nim b/compiler/passes.nim index f9c3d75f9..96088bd88 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -170,7 +170,11 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) = openPasses(a, module) if stream == nil: let filename = fileIdx.toFullPathConsiderDirty - s = llStreamOpen(filename, fmRead) + if module.name.s == "-": + module.name.s = "stdinfile" + s = llStreamOpen(stdin) + else: + s = llStreamOpen(filename, fmRead) if s == nil: rawMessage(errCannotOpenFile, filename) return diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 204bfbf94..ccf3837ed 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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]) diff --git a/compiler/sem.nim b/compiler/sem.nim index a90948245..36c0342cd 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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! diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 9077f34e9..647e75b3a 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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,67 +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 - 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"): - # echo "Matches ", n.info, " ", typeToString(sym.typ) - # debug sym - # writeMatches(z) - 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 == "*" 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 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)) @@ -153,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) @@ -173,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 @@ -182,7 +195,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, if nfExplicitCall in n.flags: tryOp ".()" - + if result.state in {csEmpty, csNoMatch}: tryOp "." @@ -193,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 @@ -218,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: @@ -248,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) @@ -319,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) @@ -335,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) @@ -355,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)) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 89469ae50..3d2ba2568 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -24,7 +24,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # same as 'semExprWithType' but doesn't check for proc vars result = semExpr(c, n, flags + {efOperand}) - if result.kind == nkEmpty: + if result.kind == nkEmpty: # do not produce another redundant error message: #raiseRecoverableError("") result = errorNode(c, n) @@ -34,19 +34,19 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = elif efWantStmt in flags: result.typ = newTypeS(tyEmpty, c) else: - localError(n.info, errExprXHasNoType, + localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags+{efWantValue}) - if result.isNil or result.kind == nkEmpty: + if result.isNil or result.kind == nkEmpty: # do not produce another redundant error message: #raiseRecoverableError("") result = errorNode(c, n) if result.typ == nil or result.typ == enforceVoidContext: # we cannot check for 'void' in macros ... - localError(n.info, errExprXHasNoType, + localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) else: @@ -61,7 +61,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # do not produce another redundant error message: result = errorNode(c, n) if result.typ == nil: - localError(n.info, errExprXHasNoType, + localError(n.info, errExprXHasNoType, renderTree(result, {renderNoComments})) result.typ = errorType(c) else: @@ -70,19 +70,19 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) - + proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.ast) result.typ = s.typ result.info = n.info - -proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = + +proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.kind of skConst: markUsed(n.info, s) styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind - of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, + of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: if s.magic == mNone: result = inlineConst(n, s) else: result = newSymNode(s, n.info) @@ -167,7 +167,7 @@ proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus = else: convOK -const +const IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus = @@ -201,10 +201,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus = proc isCastable(dst, src: PType): bool = ## Checks whether the source type can be casted to the destination type. - ## Casting is very unrestrictive; casts are allowed as long as + ## Casting is very unrestrictive; casts are allowed as long as ## castDest.size >= src.size, and typeAllowed(dst, skParam) #const - # castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, + # castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, # tySequence, tyPointer, tyNil, tyOpenArray, # tyProc, tySet, tyEnum, tyBool, tyChar} if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray: @@ -213,7 +213,7 @@ proc isCastable(dst, src: PType): bool = dstSize = computeSize(dst) srcSize = computeSize(src) - if dstSize < 0: + if dstSize < 0: result = false elif srcSize < 0: result = false @@ -225,7 +225,7 @@ proc isCastable(dst, src: PType): bool = (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes) if result and src.kind == tyNil: result = dst.size <= platform.ptrSize - + proc isSymChoice(n: PNode): bool {.inline.} = result = n.kind in nkSymChoices @@ -249,7 +249,7 @@ proc semConv(c: PContext, n: PNode): PNode = maybeLiftType(targetType, c, n[0].info) result.addSon copyTree(n.sons[0]) var op = semExprWithType(c, n.sons[1]) - + if targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) result.addSon final @@ -258,7 +258,7 @@ proc semConv(c: PContext, n: PNode): PNode = result.typ = targetType addSon(result, op) - + if not isSymChoice(op): let status = checkConvertible(c, result.typ, op.typ) case status @@ -286,7 +286,7 @@ proc semConv(c: PContext, n: PNode): PNode = return it localError(n.info, errUseQualifier, op.sons[0].sym.name.s) -proc semCast(c: PContext, n: PNode): PNode = +proc semCast(c: PContext, n: PNode): PNode = ## Semantically analyze a casting ("cast[type](param)") if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode) #incl(c.p.owner.flags, sfSideEffect) @@ -295,25 +295,25 @@ proc semCast(c: PContext, n: PNode): PNode = result.typ = semTypeNode(c, n.sons[0], nil) addSon(result, copyTree(n.sons[0])) addSon(result, semExprWithType(c, n.sons[1])) - if not isCastable(result.typ, result.sons[1].typ): - localError(result.info, errExprCannotBeCastedToX, + if not isCastable(result.typ, result.sons[1].typ): + localError(result.info, errExprCannotBeCastedToX, typeToString(result.typ)) -proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = - const +proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = + const opToStr: array[mLow..mHigh, string] = ["low", "high"] - if sonsLen(n) != 2: + if sonsLen(n) != 2: localError(n.info, errXExpectsTypeOrValue, opToStr[m]) - else: + else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyFieldAccessor}) case typ.kind - of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: + of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: n.typ = getSysType(tyInt) - of tyArrayConstr, tyArray: + of tyArrayConstr, tyArray: n.typ = typ.sons[0] # indextype - of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: + of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: # do not skip the range! n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor}) of tyGenericParam: @@ -334,8 +334,8 @@ proc semSizeof(c: PContext, n: PNode): PNode = n.typ = getSysType(tyInt) result = n -proc semOf(c: PContext, n: PNode): PNode = - if sonsLen(n) == 3: +proc semOf(c: PContext, n: PNode): PNode = + if sonsLen(n) == 3: n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType}) #restoreOldStyleType(n.sons[1]) @@ -373,7 +373,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = internalAssert n.sonsLen == 3 and n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - + let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor}) if n[2].kind in {nkStrLit..nkTripleStrLit}: @@ -381,7 +381,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = of "closure": let t = skipTypes(t1, abstractRange) result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and + t.callConv == ccClosure and tfIterator notin t.flags)) else: discard else: @@ -400,7 +400,7 @@ proc semIs(c: PContext, n: PNode): PNode = result = n n.typ = getSysType(tyBool) - + n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator}) if n[2].kind notin {nkStrLit..nkTripleStrLit}: let t2 = semTypeNode(c, n[2], nil) @@ -420,7 +420,7 @@ proc semOpAux(c: PContext, n: PNode) = const flags = {efDetermineType} for i in countup(1, n.sonsLen-1): var a = n.sons[i] - if a.kind == nkExprEqExpr and sonsLen(a) == 2: + if a.kind == nkExprEqExpr and sonsLen(a) == 2: var info = a.sons[0].info a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info) a.sons[1] = semExprWithType(c, a.sons[1], flags) @@ -428,7 +428,7 @@ proc semOpAux(c: PContext, n: PNode) = else: n.sons[i] = semExprWithType(c, a, flags) -proc overloadedCallOpr(c: PContext, n: PNode): PNode = +proc overloadedCallOpr(c: PContext, n: PNode): PNode = # quick check if there is *any* () operator overloaded: var par = getIdent("()") if searchInScopes(c, par) == nil: @@ -457,7 +457,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = return if tup.n != nil: var f = getSymFromList(newType.n, m.sym.name) - if f == nil: + if f == nil: internalError(m.info, "changeType(): invalid identifier") return changeType(n.sons[i].sons[1], f.typ, check) @@ -481,10 +481,10 @@ proc changeType(n: PNode, newType: PType, check: bool) = else: discard n.typ = newType -proc arrayConstrType(c: PContext, n: PNode): PType = +proc arrayConstrType(c: PContext, n: PNode): PType = var typ = newTypeS(tyArrayConstr, c) rawAddSon(typ, nil) # index type - if sonsLen(n) == 0: + if sonsLen(n) == 0: rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: var x = n.sons[0] @@ -494,35 +494,35 @@ proc arrayConstrType(c: PContext, n: PNode): PType = typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info) result = typ -proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = +proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newNodeI(nkBracket, n.info) result.typ = newTypeS(tyArrayConstr, c) rawAddSon(result.typ, nil) # index type - if sonsLen(n) == 0: + if sonsLen(n) == 0: rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: var x = n.sons[0] var lastIndex: BiggestInt = 0 var indexType = getSysType(tyInt) - if x.kind == nkExprColonExpr and sonsLen(x) == 2: + if x.kind == nkExprColonExpr and sonsLen(x) == 2: var idx = semConstExpr(c, x.sons[0]) lastIndex = getOrdValue(idx) indexType = idx.typ x = x.sons[1] - + let yy = semExprWithType(c, x) var typ = yy.typ addSon(result, yy) #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal}) - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): x = n.sons[i] - if x.kind == nkExprColonExpr and sonsLen(x) == 2: + if x.kind == nkExprColonExpr and sonsLen(x) == 2: var idx = semConstExpr(c, x.sons[0]) idx = fitNode(c, indexType, idx) if lastIndex+1 != getOrdValue(idx): localError(x.info, errInvalidOrderInArrayConstructor) x = x.sons[1] - + let xx = semExprWithType(c, x, flags*{efAllowDestructor}) result.add xx typ = commonType(typ, xx.typ) @@ -534,21 +534,21 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result.sons[i] = fitNode(c, typ, result.sons[i]) result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info) -proc fixAbstractType(c: PContext, n: PNode) = +proc fixAbstractType(c: PContext, n: PNode) = # XXX finally rewrite that crap! - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var it = n.sons[i] case it.kind of nkHiddenStdConv, nkHiddenSubConv: if it.sons[1].kind == nkBracket: it.sons[1].typ = arrayConstrType(c, it.sons[1]) #it.sons[1] = semArrayConstr(c, it.sons[1]) - if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: + if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="): # debug(n) - + var s = skipTypes(it.sons[1].typ, abstractVar) - if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: + if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: s = copyType(s, getCurrOwner(), false) skipTypes(s, abstractVar).sons[1] = elemType( skipTypes(it.typ, abstractVar)) @@ -558,32 +558,32 @@ proc fixAbstractType(c: PContext, n: PNode) = skipTypes(s, abstractVar).sons[0] = elemType( skipTypes(it.typ, abstractVar)) it.sons[1].typ = s - + elif skipTypes(it.sons[1].typ, abstractVar).kind in - {tyNil, tyArrayConstr, tyTuple, tySet}: + {tyNil, tyArrayConstr, tyTuple, tySet}: var s = skipTypes(it.typ, abstractVar) if s.kind != tyExpr: changeType(it.sons[1], s, check=true) n.sons[i] = it.sons[1] - of nkBracket: + of nkBracket: # an implicitly constructed array (passed to an open array): n.sons[i] = semArrayConstr(c, it, {}) - else: + else: discard - #if (it.typ == nil): - # InternalError(it.info, "fixAbstractType: " & renderTree(it)) - -proc skipObjConv(n: PNode): PNode = + #if (it.typ == nil): + # InternalError(it.info, "fixAbstractType: " & renderTree(it)) + +proc skipObjConv(n: PNode): PNode = case n.kind - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}: + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}: result = n.sons[1] - else: + else: result = n of nkObjUpConv, nkObjDownConv: result = n.sons[0] else: result = n -proc isAssignable(c: PContext, n: PNode): TAssignableResult = +proc isAssignable(c: PContext, n: PNode): TAssignableResult = result = parampatterns.isAssignable(c.p.owner, n) proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = @@ -597,49 +597,49 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = if isAssignable(c, n) notin {arLValue, arLocalLValue}: localError(n.info, errVarForOutParamNeeded) -proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = +proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n case n.kind of nkSym: # n.sym.typ can be nil in 'check' mode ... if n.sym.typ != nil and - skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: + skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: incl(n.sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) - of nkDotExpr: + of nkDotExpr: checkSonsLen(n, 2) - if n.sons[1].kind != nkSym: + if n.sons[1].kind != nkSym: internalError(n.info, "analyseIfAddressTaken") return - if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: + if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: incl(n.sons[1].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) - of nkBracketExpr: + of nkBracketExpr: checkMinSonsLen(n, 1) - if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar: + if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar: if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) - else: + else: result = newHiddenAddrTaken(c, n) - -proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = + +proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = checkMinSonsLen(n, 1) - const - FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, - mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, + const + FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, + mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy} - + # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them var t = n.sons[0].typ.skipTypes({tyGenericInst}) - if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams: + if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams: # BUGFIX: check for L-Value still needs to be done for the arguments! # note sometimes this is eval'ed twice so we check for nkHiddenAddr here: - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): if i < sonsLen(t) and t.sons[i] != nil and - skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: - if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: + skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: + if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: if n.sons[i].kind != nkHiddenAddr: localError(n.sons[i].info, errVarForOutParamNeeded) return @@ -653,14 +653,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: if n.sons[i].kind != nkHiddenAddr: n.sons[i] = analyseIfAddressTaken(c, n.sons[i]) - + include semmagic proc evalAtCompileTime(c: PContext, n: PNode): PNode = result = n if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return var callee = n.sons[0].sym - + # constant folding that is necessary for correctness of semantic pass: if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil: var call = newNodeIT(nkCall, n.info, n.typ) @@ -678,7 +678,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if result.isNil: result = n else: return result result.typ = semfold.getIntervalType(callee.magic, call) - + block maybeLabelAsStatic: # XXX: temporary work-around needed for tlateboundstatic. # This is certainly not correct, but it will get the job @@ -696,15 +696,15 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = # optimization pass: not necessary for correctness of the semantic pass if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and {sfForward, sfImportc} * callee.flags == {} and n.typ != nil: - if sfCompileTime notin callee.flags and + if sfCompileTime notin callee.flags and optImplicitStatic notin gOptions: return if callee.magic notin ctfeWhitelist: return if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine: return - + if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return - + var call = newNodeIT(nkCall, n.info, n.typ) call.add(n.sons[0]) for i in 1 .. < n.len: @@ -714,7 +714,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: result = evalStaticExpr(c.module, call, c.p.owner) - if result.isNil: + if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: @@ -737,17 +737,17 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, flags: TExprFlags): PNode = if flags*{efInTypeof, efWantIterator} != {}: # consider: 'for x in pReturningArray()' --> we don't want the restriction - # to 'skIterators' anymore; skIterators are preferred in sigmatch already + # to 'skIterators' anymore; skIterators are preferred in sigmatch already # for typeof support. # for ``type(countup(1,3))``, see ``tests/ttoseq``. result = semOverloadedCall(c, n, nOrig, {skProc, skMethod, skConverter, skMacro, skTemplate}+skIterators) else: - result = semOverloadedCall(c, n, nOrig, + result = semOverloadedCall(c, n, nOrig, {skProc, skMethod, skConverter, skMacro, skTemplate}) - + if result != nil: - if result.sons[0].kind != nkSym: + if result.sons[0].kind != nkSym: internalError("semOverloadedCallAnalyseEffects") return let callee = result.sons[0].sym @@ -759,7 +759,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) - if sfNoSideEffect notin callee.flags: + if sfNoSideEffect notin callee.flags: if {sfImportc, sfSideEffect} * callee.flags != {}: incl(c.p.owner.flags, sfSideEffect) @@ -808,11 +808,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = else: var hasErrorType = false var msg = msgKindToString(errTypeMismatch) - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): if i > 1: add(msg, ", ") let nt = n.sons[i].typ add(msg, typeToString(nt)) - if nt.kind == tyError: + if nt.kind == tyError: hasErrorType = true break if not hasErrorType: @@ -824,7 +824,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = else: result = m.call instGenericConvertersSons(c, result, m) - # we assume that a procedure that calls something indirectly + # we assume that a procedure that calls something indirectly # has side-effects: if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect) elif t != nil and t.kind == tyTypeDesc: @@ -834,7 +834,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = overloadedCallOpr(c, n) # Now that nkSym does not imply an iteration over the proc/iterator space, # the old ``prc`` (which is likely an nkIdent) has to be restored: - if result == nil: + if result == nil: # XXX: hmm, what kind of symbols will end up here? # do we really need to try the overload resolution? n.sons[0] = prc @@ -869,7 +869,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = if c.inTypeClass == 0: result = evalAtCompileTime(c, result) -proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = +proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # this seems to be a hotspot in the compiler! let nOrig = n.copyTree #semLazyOpAux(c, n) @@ -877,7 +877,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if result != nil: result = afterCallActions(c, result, nOrig, flags) else: result = errorNode(c, n) -proc buildEchoStmt(c: PContext, n: PNode): PNode = +proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) var e = strTableGet(magicsys.systemModule.tab, getIdent"echo") @@ -892,8 +892,8 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = proc semExprNoType(c: PContext, n: PNode): PNode = result = semExpr(c, n, {efWantStmt}) discardCheck(c, result) - -proc isTypeExpr(n: PNode): bool = + +proc isTypeExpr(n: PNode): bool = case n.kind of nkType, nkTypeOfExpr: result = true of nkSym: result = n.sym.kind == skType @@ -904,24 +904,24 @@ proc createSetType(c: PContext; baseType: PType): PType = result = newTypeS(tySet, c) rawAddSon(result, baseType) -proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, - check: var PNode): PSym = +proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, + check: var PNode): PSym = # transform in a node that contains the runtime check for the # field, if it is in a case-part... result = nil case r.kind - of nkRecList: - for i in countup(0, sonsLen(r) - 1): + of nkRecList: + for i in countup(0, sonsLen(r) - 1): result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check) - if result != nil: return - of nkRecCase: + if result != nil: return + of nkRecCase: checkMinSonsLen(r, 2) if (r.sons[0].kind != nkSym): illFormedAst(r) result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check) - if result != nil: return + if result != nil: return let setType = createSetType(c, r.sons[0].typ) var s = newNodeIT(nkCurly, r.info, setType) - for i in countup(1, sonsLen(r) - 1): + for i in countup(1, sonsLen(r) - 1): var it = r.sons[i] case it.kind of nkOfBranch: @@ -957,14 +957,14 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, addSon(check, notExpr) return else: illFormedAst(it) - of nkSym: + of nkSym: if r.sym.name.id == field.id: result = r.sym else: illFormedAst(n) -proc makeDeref(n: PNode): PNode = +proc makeDeref(n: PNode): PNode = var t = skipTypes(n.typ, {tyGenericInst}) result = n - if t.kind == tyVar: + if t.kind == tyVar: result = newNodeIT(nkHiddenDeref, n.info, t.sons[0]) addSon(result, n) t = skipTypes(t.sons[0], {tyGenericInst}) @@ -1079,7 +1079,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = check.sons[0] = n check.typ = n.typ result = check - elif ty.kind == tyTuple and ty.n != nil: + elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: markUsed(n.sons[1].info, f) @@ -1106,8 +1106,8 @@ proc dotTransformation(c: PContext, n: PNode): PNode = result.flags.incl nfDotField addSon(result, newIdentNode(i, n[1].info)) addSon(result, copyTree(n[0])) - -proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = + +proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # this is difficult, because the '.' is used in many different contexts # in Nim. We first allow types in the semantic checking. result = builtinFieldAccess(c, n, flags) @@ -1118,7 +1118,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = result = newNodeI(nkCall, n.info) result.add(newIdentNode(ident, n.info)) for i in 0 .. n.len-1: result.add(n[i]) - + proc semDeref(c: PContext, n: PNode): PNode = checkSonsLen(n, 1) n.sons[0] = semExprWithType(c, n.sons[0]) @@ -1127,12 +1127,12 @@ proc semDeref(c: PContext, n: PNode): PNode = case t.kind of tyRef, tyPtr: n.typ = t.lastSon else: result = nil - #GlobalError(n.sons[0].info, errCircumNeedsPointer) + #GlobalError(n.sons[0].info, errCircumNeedsPointer) proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if not a built-in subscript operator; also called for the ## checking of assignments - if sonsLen(n) == 1: + if sonsLen(n) == 1: var x = semDeref(c, n) if x == nil: return nil result = newNodeIT(nkDerefExpr, x.info, x.typ) @@ -1142,12 +1142,12 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = n.sons[0] = semExprWithType(c, n.sons[0]) var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind - of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, + of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, tyCString: if n.len != 2: return nil n.sons[0] = makeDeref(n.sons[0]) - for i in countup(1, sonsLen(n) - 1): - n.sons[i] = semExprWithType(c, n.sons[i], + for i in countup(1, sonsLen(n) - 1): + n.sons[i] = semExprWithType(c, n.sons[i], flags*{efInTypeof, efDetermineType}) var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt) var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) @@ -1157,28 +1157,28 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.typ = elemType(arr) #GlobalError(n.info, errIndexTypesDoNotMatch) of tyTypeDesc: - # The result so far is a tyTypeDesc bound + # The result so far is a tyTypeDesc bound # a tyGenericBody. The line below will substitute # it with the instantiated type. result = n result.typ = makeTypeDesc(c, semTypeNode(c, n, nil)) #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) - of tyTuple: + of tyTuple: checkSonsLen(n, 2) n.sons[0] = makeDeref(n.sons[0]) # [] operator for tuples requires constant expression: n.sons[1] = semConstExpr(c, n.sons[1]) if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in - {tyInt..tyInt64}: + {tyInt..tyInt64}: var idx = getOrdValue(n.sons[1]) if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] else: localError(n.info, errInvalidIndexValueForTuple) - else: + else: localError(n.info, errIndexTypesDoNotMatch) result = n else: discard - -proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = + +proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semSubscript(c, n, flags) if result == nil: # overloaded [] operator: @@ -1195,7 +1195,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = result.flags.incl nfDotSetter let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]]) result = semOverloadedCallAnalyseEffects(c, result, orig, {}) - + if result != nil: result = afterCallActions(c, result, nOrig, {}) #fixAbstractType(c, result) @@ -1216,7 +1216,7 @@ proc takeImplicitAddr(c: PContext, n: PNode): PNode = localError(n.info, errExprHasNoAddress) result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) result.add(n) - + proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le.sons[0] @@ -1265,7 +1265,7 @@ proc semAsgn(c: PContext, n: PNode): PNode = # a = b # both are vars, means: a[] = b[] # a = b # b no 'var T' means: a = addr(b) var le = a.typ - if skipTypes(le, {tyGenericInst}).kind != tyVar and + if skipTypes(le, {tyGenericInst}).kind != tyVar and isAssignable(c, a) == arNone: # Direct assignment to a discriminant is allowed! localError(a.info, errXCannotBeAssignedTo, @@ -1275,7 +1275,7 @@ proc semAsgn(c: PContext, n: PNode): PNode = lhs = n.sons[0] lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult var - rhs = semExprWithType(c, n.sons[1], + rhs = semExprWithType(c, n.sons[1], if lhsIsResult: {efAllowDestructor} else: {}) if lhsIsResult: n.typ = enforceVoidContext @@ -1300,13 +1300,13 @@ proc semReturn(c: PContext, n: PNode): PNode = skClosureIterator}: if n.sons[0].kind != nkEmpty: # transform ``return expr`` to ``result = expr; return`` - if c.p.resultSym != nil: + if c.p.resultSym != nil: var a = newNodeI(nkAsgn, n.sons[0].info) addSon(a, newSymNode(c.p.resultSym)) addSon(a, n.sons[0]) n.sons[0] = semAsgn(c, a) # optimize away ``result = result``: - if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: + if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: n.sons[0] = ast.emptyNode else: localError(n.info, errNoReturnTypeDeclared) @@ -1315,7 +1315,7 @@ proc semReturn(c: PContext, n: PNode): PNode = proc semProcBody(c: PContext, n: PNode): PNode = openScope(c) - + result = semExpr(c, n) if c.p.resultSym != nil and not isEmptyType(result.typ): # transform ``expr`` to ``result = expr``, but not if the expr is already @@ -1339,7 +1339,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = result = semAsgn(c, a) else: discardCheck(c, result) - + if c.p.owner.kind notin {skMacro, skTemplate} and c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: if isEmptyType(result.typ): @@ -1362,14 +1362,14 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = if e.kind == tyVar: if n.sons[0].kind == nkPar: n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i]) - elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and + elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and n.sons[0].sons[1].kind == nkPar: var a = n.sons[0].sons[1] a.sons[i] = takeImplicitAddr(c, a.sons[i]) else: localError(n.sons[0].info, errXExpected, "tuple constructor") else: discard - + proc semYield(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1) @@ -1387,14 +1387,14 @@ proc semYield(c: PContext, n: PNode): PNode = if adjustedRes.kind != tyExpr: n.sons[0] = fitNode(c, adjustedRes, n.sons[0]) if n.sons[0].typ == nil: internalError(n.info, "semYield") - + if resultTypeIsInferrable(adjustedRes): let inferred = n.sons[0].typ if restype.kind == tyIter: restype.sons[0] = inferred else: iterType.sons[0] = inferred - + semYieldVarResult(c, n, adjustedRes) else: localError(n.info, errCannotReturnExpr) @@ -1402,25 +1402,25 @@ proc semYield(c: PContext, n: PNode): PNode = localError(n.info, errGenerated, "yield statement must yield a value") proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = - if onlyCurrentScope: + if onlyCurrentScope: result = localSearchInScope(c, i) - else: + else: result = searchInScopes(c, i) # no need for stub loading -proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = +proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = case n.kind - of nkIdent: + of nkIdent: result = lookUpForDefined(c, n.ident, onlyCurrentScope) of nkDotExpr: result = nil - if onlyCurrentScope: return + if onlyCurrentScope: return checkSonsLen(n, 2) var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope) if m != nil and m.kind == skModule: let ident = considerQuotedIdent(n[1]) if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident) - else: + else: result = strTableGet(m.tab, ident) of nkAccQuoted: result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope) @@ -1432,7 +1432,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = localError(n.info, errIdentifierExpected, renderTree(n)) result = nil -proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = +proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = checkSonsLen(n, 2) # we replace this node by a 'true' or 'false' node: result = newIntNode(nkIntLit, 0) @@ -1441,7 +1441,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = localError(n.info, "obsolete usage of 'defined', use 'declared' instead") elif condsyms.isDefined(n.sons[1].ident): result.intVal = 1 - elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: + elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: result.intVal = 1 result.info = n.info result.typ = getSysType(tyBool) @@ -1544,7 +1544,7 @@ proc processQuotations(n: var PNode, op: string, n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info) elif n.kind == nkAccQuoted and op == "``": returnQuote n[0] - + for i in 0 .. <n.safeLen: processQuotations(n.sons[i], op, quotes, ids) @@ -1556,7 +1556,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = doBlk = n{-1} op = if n.len == 3: expectString(c, n[1]) else: "``" quotes = newSeq[PNode](1) - # the quotes will be added to a nkCall statement + # the quotes will be added to a nkCall statement # leave some room for the callee symbol ids = newSeq[PNode]() # this will store the generated param names @@ -1565,7 +1565,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = localError(n.info, errXExpected, "block") processQuotations(doBlk.sons[bodyPos], op, quotes, ids) - + doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode if ids.len > 0: doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info) @@ -1573,7 +1573,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = ids.add getSysSym("expr").newSymNode # params type ids.add emptyNode # no default value doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids) - + var tmpl = semTemplateDef(c, doBlk) quotes[0] = tmpl[namePos] result = newNode(nkCall, n.info, @[ @@ -1588,7 +1588,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = inc c.inCompilesContext # do not halt after first error: msgs.gErrorMax = high(int) - + # open a scope for temporary symbol inclusions: let oldScope = c.currentScope openScope(c) @@ -1597,7 +1597,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = let oldErrorOutputs = errorOutputs errorOutputs = {} let oldContextLen = msgs.getInfoContextLen() - + let oldInGenericContext = c.inGenericContext let oldInUnrolledContext = c.inUnrolledContext let oldInGenericInst = c.inGenericInst @@ -1625,7 +1625,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: if sonsLen(n) != 2: return semDirectOp(c, n, flags) - + result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil)) result.info = n.info result.typ = getSysType(tyBool) @@ -1652,7 +1652,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; let sym = magicsys.getCompilerProc("nimCreateFlowVar") if sym == nil: localError(info, errSystemNeeds, "nimCreateFlowVar") - var bindings: TIdTable + var bindings: TIdTable initIdTable(bindings) bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t) result = c.semGenerateInstance(c, sym, bindings, info) @@ -1662,12 +1662,12 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC} result.loc.r = nil -proc setMs(n: PNode, s: PSym): PNode = +proc setMs(n: PNode, s: PSym): PNode = result = n n.sons[0] = newSymNode(s) n.sons[0].info = n.info -proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = +proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # this is a hotspot in the compiler! # DON'T forget to update ast.SpecialSemMagics if you add a magic here! result = n @@ -1713,36 +1713,36 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = # If semCheck is set to false, ``when`` will return the verbatim AST of # the correct branch. Otherwise the AST will be passed through semStmt. result = nil - + template setResult(e: expr) = if semCheck: result = semStmt(c, e) # do not open a new scope! else: result = e - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] case it.kind - of nkElifBranch, nkElifExpr: + of nkElifBranch, nkElifExpr: checkSonsLen(it, 2) var e = semConstExpr(c, it.sons[0]) - if e.kind != nkIntLit: + if e.kind != nkIntLit: # can happen for cascading errors, assume false # InternalError(n.info, "semWhen") discard elif e.intVal != 0 and result == nil: - setResult(it.sons[1]) + setResult(it.sons[1]) of nkElse, nkElseExpr: checkSonsLen(it, 1) - if result == nil: + if result == nil: setResult(it.sons[0]) else: illFormedAst(n) if result == nil: - result = newNodeI(nkEmpty, n.info) + result = newNodeI(nkEmpty, n.info) # The ``when`` statement implements the mechanism for platform dependent # code. Thus we try to ensure here consistent ID allocation after the # ``when`` statement. idSynchronizationPoint(200) -proc semSetConstr(c: PContext, n: PNode): PNode = +proc semSetConstr(c: PContext, n: PNode): PNode = result = newNodeI(nkCurly, n.info) result.typ = newTypeS(tySet, c) if sonsLen(n) == 0: @@ -1750,31 +1750,31 @@ proc semSetConstr(c: PContext, n: PNode): PNode = else: # only semantic checking for all elements, later type checking: var typ: PType = nil - for i in countup(0, sonsLen(n) - 1): - if isRange(n.sons[i]): + for i in countup(0, sonsLen(n) - 1): + if isRange(n.sons[i]): checkSonsLen(n.sons[i], 3) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1]) n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2]) - if typ == nil: - typ = skipTypes(n.sons[i].sons[1].typ, + if typ == nil: + typ = skipTypes(n.sons[i].sons[1].typ, {tyGenericInst, tyVar, tyOrdinal}) n.sons[i].typ = n.sons[i].sons[2].typ # range node needs type too elif n.sons[i].kind == nkRange: # already semchecked if typ == nil: - typ = skipTypes(n.sons[i].sons[0].typ, + typ = skipTypes(n.sons[i].sons[0].typ, {tyGenericInst, tyVar, tyOrdinal}) else: n.sons[i] = semExprWithType(c, n.sons[i]) - if typ == nil: + if typ == nil: typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyOrdinal}) if not isOrdinalType(typ): localError(n.info, errOrdinalTypeExpected) typ = makeRangeType(c, 0, MaxSetElements-1, n.info) - elif lengthOrd(typ) > MaxSetElements: + elif lengthOrd(typ) > MaxSetElements: typ = makeRangeType(c, 0, MaxSetElements-1, n.info) addSonSkipIntLit(result.typ, typ) - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var m: PNode if isRange(n.sons[i]): m = newNodeI(nkRange, n.sons[i].info) @@ -1786,7 +1786,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = addSon(result, m) proc semTableConstr(c: PContext, n: PNode): PNode = - # we simply transform ``{key: value, key2, key3: value}`` to + # we simply transform ``{key: value, key2, key3: value}`` to # ``[(key, value), (key2, value2), (key3, value2)]`` result = newNodeI(nkBracket, n.info) var lastKey = 0 @@ -1815,7 +1815,7 @@ type proc checkPar(n: PNode): TParKind = var length = sonsLen(n) - if length == 0: + if length == 0: result = paTuplePositions # () elif length == 1: if n.sons[0].kind == nkExprColonExpr: result = paTupleFields @@ -1845,7 +1845,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var id: PIdent if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident else: id = n.sons[i].sons[0].sym.name - if containsOrIncl(ids, id.id): + if containsOrIncl(ids, id.id): localError(n.sons[i].info, errFieldInitTwice, id.s) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1], flags*{efAllowDestructor}) @@ -1858,14 +1858,22 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = addSon(result, n.sons[i]) result.typ = typ -proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = +proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result = n # we don't modify n, but compute the type: var typ = newTypeS(tyTuple, c) # leave typ.n nil! - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor}) addSonSkipIntLit(typ, n.sons[i].typ) result.typ = typ +proc isTupleType(n: PNode): bool = + if n.len == 0: + return false # don't interpret () as type + for i in countup(0, n.len - 1): + if n[i].typ == nil or n[i].typ.kind != tyTypeDesc: + return false + return true + proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) = case n.kind of nkRecList: @@ -1991,10 +1999,10 @@ proc setGenericParams(c: PContext, n: PNode) = for i in 1 .. <n.len: n[i].typ = semTypeNode(c, n[i], nil) -proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = +proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n if gCmd == cmdIdeTools: suggestExpr(c, n) - if nfSem in n.flags: return + if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: var s = lookUp(c, n) @@ -2011,43 +2019,43 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! result = semSym(c, n, n.sym, flags) - of nkEmpty, nkNone, nkCommentStmt: + of nkEmpty, nkNone, nkCommentStmt: discard - of nkNilLit: + of nkNilLit: result.typ = getSysType(tyNil) of nkIntLit: if result.typ == nil: setIntLitType(result) of nkInt8Lit: if result.typ == nil: result.typ = getSysType(tyInt8) - of nkInt16Lit: + of nkInt16Lit: if result.typ == nil: result.typ = getSysType(tyInt16) - of nkInt32Lit: + of nkInt32Lit: if result.typ == nil: result.typ = getSysType(tyInt32) - of nkInt64Lit: + of nkInt64Lit: if result.typ == nil: result.typ = getSysType(tyInt64) of nkUIntLit: if result.typ == nil: result.typ = getSysType(tyUInt) - of nkUInt8Lit: + of nkUInt8Lit: if result.typ == nil: result.typ = getSysType(tyUInt8) - of nkUInt16Lit: + of nkUInt16Lit: if result.typ == nil: result.typ = getSysType(tyUInt16) - of nkUInt32Lit: + of nkUInt32Lit: if result.typ == nil: result.typ = getSysType(tyUInt32) - of nkUInt64Lit: + of nkUInt64Lit: if result.typ == nil: result.typ = getSysType(tyUInt64) - of nkFloatLit: + of nkFloatLit: if result.typ == nil: result.typ = getFloatLitType(result) - of nkFloat32Lit: + of nkFloat32Lit: if result.typ == nil: result.typ = getSysType(tyFloat32) - of nkFloat64Lit: + of nkFloat64Lit: if result.typ == nil: result.typ = getSysType(tyFloat64) - of nkFloat128Lit: + of nkFloat128Lit: if result.typ == nil: result.typ = getSysType(tyFloat128) - of nkStrLit..nkTripleStrLit: + of nkStrLit..nkTripleStrLit: if result.typ == nil: result.typ = getSysType(tyString) - of nkCharLit: + of nkCharLit: if result.typ == nil: result.typ = getSysType(tyChar) - of nkDotExpr: + of nkDotExpr: result = semFieldAccess(c, n, flags) if result.kind == nkDotCall: result.kind = nkCall @@ -2055,11 +2063,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkBind: message(n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) - of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy: + of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter}) result.typ = makeTypeDesc(c, typ) #result = symNodeFromType(c, typ, n.info) - of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: + of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} @@ -2084,7 +2092,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semConv(c, n) elif n.len == 1: result = semObjConstr(c, n, flags) - elif contains(c.ambiguousSymbols, s.id): + elif contains(c.ambiguousSymbols, s.id): localError(n.info, errUseQualifier, s.name.s) elif s.magic == mNone: result = semDirectOp(c, n, flags) else: result = semMagic(c, n, s, flags) @@ -2123,13 +2131,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semArrayAccess(c, n, flags) of nkCurlyExpr: result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) - of nkPragmaExpr: + of nkPragmaExpr: # which pragmas are allowed for expressions? `likely`, `unlikely` internalError(n.info, "semExpr() to implement") # XXX: to implement - of nkPar: + of nkPar: case checkPar(n) of paNone: result = errorNode(c, n) - of paTuplePositions: result = semTuplePositionsConstr(c, n, flags) + of paTuplePositions: + var tupexp = semTuplePositionsConstr(c, n, flags) + if isTupleType(tupexp): + # reinterpret as type + var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter}) + result.typ = makeTypeDesc(c, typ) + else: + result = tupexp of paTupleFields: result = semTupleFieldsConstr(c, n, flags) of paSingle: result = semExpr(c, n.sons[0], flags) of nkCurly: result = semSetConstr(c, n) @@ -2142,7 +2157,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n checkSonsLen(n, 1) n.sons[0] = semExprWithType(c, n.sons[0]) - if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: + if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: localError(n.info, errExprHasNoAddress) n.typ = makePtrType(c, n.sons[0].typ) of nkHiddenAddr, nkHiddenDeref: @@ -2150,13 +2165,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = n.sons[0] = semExpr(c, n.sons[0], flags) of nkCast: result = semCast(c, n) of nkIfExpr, nkIfStmt: result = semIf(c, n) - of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: + of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: checkSonsLen(n, 2) - of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: + of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: checkSonsLen(n, 1) - of nkChckRangeF, nkChckRange64, nkChckRange: + of nkChckRangeF, nkChckRange64, nkChckRange: checkSonsLen(n, 3) - of nkCheckedFieldExpr: + of nkCheckedFieldExpr: checkMinSonsLen(n, 2) of nkTableConstr: result = semTableConstr(c, n) @@ -2191,16 +2206,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkConverterDef: result = semConverterDef(c, n) of nkMacroDef: result = semMacroDef(c, n) of nkTemplateDef: result = semTemplateDef(c, n) - of nkImportStmt: + of nkImportStmt: if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import") result = evalImport(c, n) of nkImportExceptStmt: if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import") result = evalImportExcept(c, n) - of nkFromStmt: + of nkFromStmt: if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from") result = evalFrom(c, n) - of nkIncludeStmt: + of nkIncludeStmt: if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include") result = evalInclude(c, n) of nkExportStmt, nkExportExceptStmt: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 2601f05ac..db910600b 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -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) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index a10f27519..dc36ecf34 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -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() diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 60153e052..14644a8d6 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 42471bae7..ccfd74607 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -692,7 +692,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = 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 @@ -757,7 +757,8 @@ proc lookupMacro(c: PContext, n: PNode): PSym = else: result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate}) -proc semProcAnnotation(c: PContext, prc: PNode): PNode = +proc semProcAnnotation(c: PContext, prc: PNode; + validPragmas: TSpecialWords): PNode = var n = prc.sons[pragmasPos] if n == nil or n.kind == nkEmpty: return for i in countup(0, <n.len): @@ -782,12 +783,18 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode = x.add(it.sons[1]) x.add(prc) # recursion assures that this works for multiple macro annotations too: - return semStmt(c, x) + 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.kind in procDefs and result[namePos].kind == nkSym and + result[pragmasPos].kind != nkEmpty: + pragma(c, result[namePos].sym, result[pragmasPos], validPragmas) + return proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX semProcAux should be good enough for this now, we will eventually # remove semLambda - result = semProcAnnotation(c, n) + result = semProcAnnotation(c, n, lambdaPragmas) if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) @@ -943,7 +950,7 @@ proc isForwardDecl(s: PSym): bool = proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords, phase = stepRegisterSymbol): PNode = - result = semProcAnnotation(c, n) + result = semProcAnnotation(c, n, validPragmas) if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 9f2f755a0..ac0636211 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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 diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 86826567e..012782730 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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: @@ -390,9 +392,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: result = n.typ - of tyInt: + of tyInt, tyFloat: result = skipIntLit(t) - # XXX now there are also float literals of tyTypeDesc: let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t) diff --git a/compiler/service.nim b/compiler/service.nim index 1d51ef2a1..7cb9d7d29 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -33,7 +33,12 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = parseopt.next(p) case p.kind of cmdEnd: break - of cmdLongoption, cmdShortOption: processSwitch(pass, p) + of cmdLongoption, cmdShortOption: + if p.key == " ": + p.key = "-" + if processArgument(pass, p, argsCount): break + else: + processSwitch(pass, p) of cmdArgument: if processArgument(pass, p, argsCount): break if pass == passCmd2: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 90d889eb0..6fb50f8e5 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 @@ -91,7 +91,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = initIdTable(c.bindings) proc put(t: var TIdTable, key, val: PType) {.inline.} = - idTablePut(t, key, val) + idTablePut(t, key, val.skipIntLit) proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) = @@ -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 @@ -176,7 +176,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 +203,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 +225,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 +241,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 +255,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 +267,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 +286,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 +318,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 +332,17 @@ 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 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,7 +373,7 @@ 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: @@ -388,17 +388,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if result <= isSubtype or inconsistentVarTypes(f, a): result = isNone - + 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 +407,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]) @@ -487,14 +487,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 +520,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 +554,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,9 +569,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isNone assert(f != nil) - + if f.kind == tyExpr: - put(c.bindings, f, aOrig) + if aOrig != nil: put(c.bindings, f, aOrig) return isGeneric assert(aOrig != nil) @@ -582,7 +582,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, @@ -626,9 +626,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 +727,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 +768,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: @@ -783,13 +783,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyDistinct: 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 +823,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 +848,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,7 +863,7 @@ 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 # XXX See bug #2220. A[int] should match A[int] better than some generic X @@ -883,13 +883,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,7 +900,7 @@ 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: @@ -914,7 +914,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = for branch in f.sons: if typeRel(c, branch, aOrig) >= isSubtype: bindingRet isGeneric - + return isNone of tyNot: @@ -922,7 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = for branch in f.sons: if typeRel(c, branch, aOrig) != isNone: return isNone - + bindingRet isGeneric of tyAnything: @@ -961,7 +961,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 @@ -1004,7 +1004,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isGeneric else: result = typeRel(c, x, a) # check if it fits - + of tyStatic: let prev = PType(idTableGet(c.bindings, f)) if prev == nil: @@ -1034,12 +1034,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 +1049,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 +1059,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyStmt: result = isGeneric - + of tyProxy: result = isEqual @@ -1078,11 +1078,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 +1095,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 +1110,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 +1121,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 +1138,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 +1181,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 +1205,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 @@ -1232,7 +1232,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, elif f.kind == tyStatic: return arg.typ.n else: - return argOrig + return argSemantized # argOrig if r != isNone and f.isInlineIterator: var inlined = newTypeS(tyStatic, c) @@ -1244,19 +1244,18 @@ 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) + result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isInferred, isInferredConvertible: inc(m.genericMatches) if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds: @@ -1269,40 +1268,32 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = implicitConv(nkHiddenStdConv, f, result, m, c) 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 +1314,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 +1328,28 @@ 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) var r = typeRel(z, f, arg.sons[i].typ) - if r != isNone: + 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 +1362,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 +1406,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 +1436,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 +1459,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 +1496,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 +1504,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 +1517,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 +1592,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 +1613,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) @@ -1662,7 +1653,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 +1661,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 +1679,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 +1703,7 @@ tests: yes seq(!int), seq(any) no seq(any), seq(!any) no seq(!int), seq(!any) - + yes int, ordinal no string, ordinal diff --git a/compiler/types.nim b/compiler/types.nim index 5c3be7553..5f506f10f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -9,20 +9,20 @@ # this module contains routines for accessing and iterating over types -import +import intsets, ast, astalgo, trees, msgs, strutils, platform, renderer proc firstOrd*(t: PType): BiggestInt proc lastOrd*(t: PType): BiggestInt proc lengthOrd*(t: PType): BiggestInt -type +type TPreferedDesc* = enum preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string proc base*(t: PType): PType # ------------------- type iterator: ---------------------------------------- -type +type TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it TTypePredicate* = proc (t: PType): bool {.nimcall.} @@ -32,7 +32,7 @@ proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType # Returns result of `iter`. -type +type TParamsEquality* = enum # they are equal, but their # identifiers or their return # type differ (i.e. they cannot be @@ -59,7 +59,7 @@ const abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal, tyTypeDesc} - skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, + skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, tyTypeDesc} typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc} @@ -75,9 +75,9 @@ proc getSize*(typ: PType): BiggestInt proc isPureObject*(typ: PType): bool proc invalidGenericInst*(f: PType): bool # for debugging -type - TTypeFieldResult* = enum - frNone, # type has no object type field +type + TTypeFieldResult* = enum + frNone, # type has no object type field frHeader, # type has an object type field only in the header frEmbedded # type has an object type field somewhere embedded @@ -86,15 +86,15 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult # made or intializing of the type field suffices or if there is no type field # at all in this type. -proc invalidGenericInst(f: PType): bool = +proc invalidGenericInst(f: PType): bool = result = f.kind == tyGenericInst and lastSon(f) == nil -proc isPureObject(typ: PType): bool = +proc isPureObject(typ: PType): bool = var t = typ while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0] result = t.sym != nil and sfPure in t.sym.flags -proc getOrdValue(n: PNode): BiggestInt = +proc getOrdValue(n: PNode): BiggestInt = case n.kind of nkCharLit..nkUInt64Lit: result = n.intVal of nkNilLit: result = 0 @@ -109,21 +109,21 @@ proc isIntLit*(t: PType): bool {.inline.} = proc isFloatLit*(t: PType): bool {.inline.} = result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit -proc isCompatibleToCString(a: PType): bool = - if a.kind == tyArray: +proc isCompatibleToCString(a: PType): bool = + if a.kind == tyArray: if (firstOrd(a.sons[0]) == 0) and - (skipTypes(a.sons[0], {tyRange, tyConst, - tyMutable, tyGenericInst}).kind in + (skipTypes(a.sons[0], {tyRange, tyConst, + tyMutable, tyGenericInst}).kind in {tyInt..tyInt64, tyUInt..tyUInt64}) and - (a.sons[1].kind == tyChar): + (a.sons[1].kind == tyChar): result = true - -proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = + +proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = result = sym.owner.name.s & '.' & sym.name.s & '(' var n = sym.typ.n - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var p = n.sons[i] - if p.kind == nkSym: + if p.kind == nkSym: add(result, p.sym.name.s) add(result, ": ") add(result, typeToString(p.sym.typ, prefer)) @@ -134,7 +134,7 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ, prefer)) -proc elemType*(t: PType): PType = +proc elemType*(t: PType): PType = assert(t != nil) case t.kind of tyGenericInst, tyDistinct: result = elemType(lastSon(t)) @@ -142,10 +142,10 @@ proc elemType*(t: PType): PType = else: result = t.lastSon assert(result != nil) -proc skipGeneric(t: PType): PType = +proc skipGeneric(t: PType): PType = result = t while result.kind == tyGenericInst: result = lastSon(result) - + proc isOrdinalType(t: PType): bool = assert(t != nil) # caution: uint, uint64 are no ordinal types! @@ -153,134 +153,134 @@ proc isOrdinalType(t: PType): bool = (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and isOrdinalType(t.sons[0]) -proc enumHasHoles(t: PType): bool = +proc enumHasHoles(t: PType): bool = var b = t while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0] result = b.kind == tyEnum and tfEnumHasHoles in b.flags -proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, closure: RootRef): bool -proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, - closure: RootRef): bool = - if n != nil: +proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, + closure: RootRef): bool = + if n != nil: case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: # a leaf result = iterOverTypeAux(marker, n.typ, iter, closure) - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): result = iterOverNode(marker, n.sons[i], iter, closure) - if result: return - -proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, - closure: RootRef): bool = + if result: return + +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool = result = false - if t == nil: return + if t == nil: return result = iter(t, closure) - if result: return - if not containsOrIncl(marker, t.id): + if result: return + if not containsOrIncl(marker, t.id): case t.kind - of tyGenericInst, tyGenericBody: + of tyGenericInst, tyGenericBody: result = iterOverTypeAux(marker, lastSon(t), iter, closure) - else: - for i in countup(0, sonsLen(t) - 1): + else: + for i in countup(0, sonsLen(t) - 1): result = iterOverTypeAux(marker, t.sons[i], iter, closure) - if result: return + if result: return if t.n != nil: result = iterOverNode(marker, t.n, iter, closure) - -proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = + +proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = var marker = initIntSet() result = iterOverTypeAux(marker, t, iter, closure) -proc searchTypeForAux(t: PType, predicate: TTypePredicate, +proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var IntSet): bool -proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, - marker: var IntSet): bool = +proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, + marker: var IntSet): bool = result = false case n.kind - of nkRecList: - for i in countup(0, sonsLen(n) - 1): + of nkRecList: + for i in countup(0, sonsLen(n) - 1): result = searchTypeNodeForAux(n.sons[i], p, marker) - if result: return - of nkRecCase: + if result: return + of nkRecCase: assert(n.sons[0].kind == nkSym) result = searchTypeNodeForAux(n.sons[0], p, marker) - if result: return - for i in countup(1, sonsLen(n) - 1): + if result: return + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkOfBranch, nkElse: + of nkOfBranch, nkElse: result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker) - if result: return + if result: return else: internalError("searchTypeNodeForAux(record case branch)") - of nkSym: + of nkSym: result = searchTypeForAux(n.sym.typ, p, marker) else: internalError(n.info, "searchTypeNodeForAux()") - -proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var IntSet): bool = + +proc searchTypeForAux(t: PType, predicate: TTypePredicate, + marker: var IntSet): bool = # iterates over VALUE types! result = false - if t == nil: return - if containsOrIncl(marker, t.id): return + if t == nil: return + if containsOrIncl(marker, t.id): return result = predicate(t) - if result: return + if result: return case t.kind - of tyObject: + of tyObject: result = searchTypeForAux(t.sons[0], predicate, marker) if not result: result = searchTypeNodeForAux(t.n, predicate, marker) - of tyGenericInst, tyDistinct: + of tyGenericInst, tyDistinct: result = searchTypeForAux(lastSon(t), predicate, marker) - of tyArray, tyArrayConstr, tySet, tyTuple: - for i in countup(0, sonsLen(t) - 1): + of tyArray, tyArrayConstr, tySet, tyTuple: + for i in countup(0, sonsLen(t) - 1): result = searchTypeForAux(t.sons[i], predicate, marker) - if result: return - else: + if result: return + else: discard -proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = +proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = var marker = initIntSet() result = searchTypeForAux(t, predicate, marker) -proc isObjectPredicate(t: PType): bool = +proc isObjectPredicate(t: PType): bool = result = t.kind == tyObject -proc containsObject(t: PType): bool = +proc containsObject(t: PType): bool = result = searchTypeFor(t, isObjectPredicate) -proc isObjectWithTypeFieldPredicate(t: PType): bool = +proc isObjectWithTypeFieldPredicate(t: PType): bool = result = t.kind == tyObject and t.sons[0] == nil and not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and tfFinal notin t.flags -proc analyseObjectWithTypeFieldAux(t: PType, - marker: var IntSet): TTypeFieldResult = +proc analyseObjectWithTypeFieldAux(t: PType, + marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult result = frNone - if t == nil: return + if t == nil: return case t.kind - of tyObject: - if (t.n != nil): - if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): + of tyObject: + if (t.n != nil): + if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): return frEmbedded - for i in countup(0, sonsLen(t) - 1): + for i in countup(0, sonsLen(t) - 1): res = analyseObjectWithTypeFieldAux(t.sons[i], marker) - if res == frEmbedded: + if res == frEmbedded: return frEmbedded if res == frHeader: result = frHeader - if result == frNone: + if result == frNone: if isObjectWithTypeFieldPredicate(t): result = frHeader - of tyGenericInst, tyDistinct, tyConst, tyMutable: + of tyGenericInst, tyDistinct, tyConst, tyMutable: result = analyseObjectWithTypeFieldAux(lastSon(t), marker) - of tyArray, tyArrayConstr, tyTuple: - for i in countup(0, sonsLen(t) - 1): + of tyArray, tyArrayConstr, tyTuple: + for i in countup(0, sonsLen(t) - 1): res = analyseObjectWithTypeFieldAux(t.sons[i], marker) - if res != frNone: + if res != frNone: return frEmbedded - else: + else: discard -proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = +proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = var marker = initIntSet() result = analyseObjectWithTypeFieldAux(t, marker) @@ -288,7 +288,7 @@ proc isGCRef(t: PType): bool = result = t.kind in GcTypeKinds or (t.kind == tyProc and t.callConv == ccClosure) -proc containsGarbageCollectedRef(typ: PType): bool = +proc containsGarbageCollectedRef(typ: PType): bool = # returns true if typ contains a reference, sequence or string (all the # things that are garbage-collected) result = searchTypeFor(typ, isGCRef) @@ -296,47 +296,47 @@ proc containsGarbageCollectedRef(typ: PType): bool = proc isTyRef(t: PType): bool = result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure) -proc containsTyRef*(typ: PType): bool = +proc containsTyRef*(typ: PType): bool = # returns true if typ contains a 'ref' result = searchTypeFor(typ, isTyRef) -proc isHiddenPointer(t: PType): bool = +proc isHiddenPointer(t: PType): bool = result = t.kind in {tyString, tySequence} -proc containsHiddenPointer(typ: PType): bool = +proc containsHiddenPointer(typ: PType): bool = # returns true if typ contains a string, table or sequence (all the things # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = +proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = result = false - if n != nil: + if n != nil: result = canFormAcycleAux(marker, n.typ, startId) - if not result: + if not result: case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: discard - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): result = canFormAcycleNode(marker, n.sons[i], startId) - if result: return - -proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = + if result: return + +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false - if typ == nil: return - if tfAcyclic in typ.flags: return + if typ == nil: return + if tfAcyclic in typ.flags: return var t = skipTypes(typ, abstractInst-{tyTypeDesc}) - if tfAcyclic in t.flags: return + if tfAcyclic in t.flags: return case t.kind of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs: - if not containsOrIncl(marker, t.id): - for i in countup(0, sonsLen(t) - 1): + if not containsOrIncl(marker, t.id): + for i in countup(0, sonsLen(t) - 1): result = canFormAcycleAux(marker, t.sons[i], startId) - if result: return + if result: return if t.n != nil: result = canFormAcycleNode(marker, t.n, startId) - else: + else: result = t.id == startId # Inheritance can introduce cyclic types, however this is not relevant # as the type that is passed to 'new' is statically known! @@ -351,29 +351,29 @@ proc canFormAcycle(typ: PType): bool = var marker = initIntSet() result = canFormAcycleAux(marker, typ, typ.id) -proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, closure: RootRef): PType -proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, - closure: RootRef): PNode = +proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, + closure: RootRef): PNode = result = nil - if n != nil: + if n != nil: result = copyNode(n) result.typ = mutateTypeAux(marker, n.typ, iter, closure) case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: # a leaf discard - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): addSon(result, mutateNode(marker, n.sons[i], iter, closure)) - -proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, - closure: RootRef): PType = + +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType = result = nil - if t == nil: return + if t == nil: return result = iter(t, closure) - if not containsOrIncl(marker, t.id): - for i in countup(0, sonsLen(t) - 1): + if not containsOrIncl(marker, t.id): + for i in countup(0, sonsLen(t) - 1): result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure) if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure) assert(result != nil) @@ -393,7 +393,7 @@ proc rangeToStr(n: PNode): string = assert(n.kind == nkRange) result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1]) -const +const typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc", "GenericInvocation", "GenericBody", "GenericInst", "GenericParam", @@ -414,7 +414,7 @@ const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ result = "" - if t == nil: return + if t == nil: return if prefer in preferToResolveSymbols and t.sym != nil and sfAnon notin t.sym.flags: if t.kind == tyInt and isIntLit(t): @@ -484,47 +484,51 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "expr" of tyFromExpr, tyFieldAccessor: result = renderTree(t.n) - of tyArray: - if t.sons[0].kind == tyRange: + of tyArray: + if t.sons[0].kind == tyRange: result = "array[" & rangeToStr(t.sons[0].n) & ", " & typeToString(t.sons[1]) & ']' - else: + else: result = "array[" & typeToString(t.sons[0]) & ", " & typeToString(t.sons[1]) & ']' - of tyArrayConstr: + of tyArrayConstr: result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " & typeToString(t.sons[1]) & ']' - of tySequence: + of tySequence: result = "seq[" & typeToString(t.sons[0]) & ']' - of tyOrdinal: + of tyOrdinal: result = "ordinal[" & typeToString(t.sons[0]) & ']' - of tySet: + of tySet: result = "set[" & typeToString(t.sons[0]) & ']' - of tyOpenArray: + of tyOpenArray: result = "openarray[" & typeToString(t.sons[0]) & ']' of tyDistinct: result = "distinct " & typeToString(t.sons[0], if prefer == preferModuleInfo: preferModuleInfo else: preferName) - of tyTuple: + of tyTuple: # we iterate over t.sons here, because t.n may be nil - result = "tuple[" - if t.n != nil: + if t.n != nil: + result = "tuple[" assert(sonsLen(t.n) == sonsLen(t)) - for i in countup(0, sonsLen(t.n) - 1): + for i in countup(0, sonsLen(t.n) - 1): assert(t.n.sons[i].kind == nkSym) add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i])) if i < sonsLen(t.n) - 1: add(result, ", ") - else: - for i in countup(0, sonsLen(t) - 1): + add(result, ']') + elif sonsLen(t) == 0: + result = "tuple[]" + else: + result = "(" + for i in countup(0, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") - add(result, ']') - of tyPtr, tyRef, tyVar, tyMutable, tyConst: + add(result, ')') + of tyPtr, tyRef, tyVar, tyMutable, tyConst: result = typeToStr[t.kind] if t.len >= 2: setLen(result, result.len-1) result.add '[' - for i in countup(0, sonsLen(t) - 1): + for i in countup(0, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") result.add ']' @@ -536,7 +540,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add("(" & typeToString(t.sons[0]) & ")") of tyProc: result = if tfIterator in t.flags: "iterator (" else: "proc (" - for i in countup(1, sonsLen(t) - 1): + for i in countup(1, sonsLen(t) - 1): add(result, typeToString(t.sons[i])) if i < sonsLen(t) - 1: add(result, ", ") add(result, ')') @@ -554,29 +558,29 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if len(prag) != 0: add(result, "{." & prag & ".}") of tyVarargs, tyIter: result = typeToStr[t.kind] % typeToString(t.sons[0]) - else: + else: result = typeToStr[t.kind] if tfShared in t.flags: result = "shared " & result if tfNotNil in t.flags: result.add(" not nil") -proc resultType(t: PType): PType = +proc resultType(t: PType): PType = assert(t.kind == tyProc) result = t.sons[0] # nil is allowed - -proc base(t: PType): PType = + +proc base(t: PType): PType = result = t.sons[0] -proc firstOrd(t: PType): BiggestInt = +proc firstOrd(t: PType): BiggestInt = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: result = 0 of tySet, tyVar: result = firstOrd(t.sons[0]) of tyArray, tyArrayConstr: result = firstOrd(t.sons[0]) - of tyRange: + of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) result = getOrdValue(t.n.sons[0]) - of tyInt: + of tyInt: if platform.intSize == 4: result = - (2147483646) - 2 else: result = 0x8000000000000000'i64 of tyInt8: result = - 128 @@ -584,11 +588,11 @@ proc firstOrd(t: PType): BiggestInt = of tyInt32: result = - 2147483646 - 2 of tyInt64: result = 0x8000000000000000'i64 of tyUInt..tyUInt64: result = 0 - of tyEnum: + of tyEnum: # if basetype <> nil then return firstOrd of basetype - if (sonsLen(t) > 0) and (t.sons[0] != nil): + if (sonsLen(t) > 0) and (t.sons[0] != nil): result = firstOrd(t.sons[0]) - else: + else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor: @@ -600,31 +604,31 @@ proc firstOrd(t: PType): BiggestInt = internalError("invalid kind for first(" & $t.kind & ')') result = 0 -proc lastOrd(t: PType): BiggestInt = +proc lastOrd(t: PType): BiggestInt = case t.kind of tyBool: result = 1 of tyChar: result = 255 of tySet, tyVar: result = lastOrd(t.sons[0]) of tyArray, tyArrayConstr: result = lastOrd(t.sons[0]) - of tyRange: + of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) result = getOrdValue(t.n.sons[1]) - of tyInt: + of tyInt: if platform.intSize == 4: result = 0x7FFFFFFF else: result = 0x7FFFFFFFFFFFFFFF'i64 of tyInt8: result = 0x0000007F of tyInt16: result = 0x00007FFF of tyInt32: result = 0x7FFFFFFF of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyUInt: + of tyUInt: if platform.intSize == 4: result = 0xFFFFFFFF else: result = 0x7FFFFFFFFFFFFFFF'i64 of tyUInt8: result = 0xFF of tyUInt16: result = 0xFFFF of tyUInt32: result = 0xFFFFFFFF of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyEnum: + of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position of tyGenericInst, tyDistinct, tyConst, tyMutable, @@ -638,7 +642,7 @@ proc lastOrd(t: PType): BiggestInt = internalError("invalid kind for last(" & $t.kind & ')') result = 0 -proc lengthOrd(t: PType): BiggestInt = +proc lengthOrd(t: PType): BiggestInt = case t.kind of tyInt64, tyInt32, tyInt: result = lastOrd(t) of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0]) @@ -654,7 +658,7 @@ type dcEqOrDistinctOf ## a equals b or a is distinct of b TTypeCmpFlag* = enum - IgnoreTupleFields + IgnoreTupleFields ## NOTE: Only set this flag for backends! IgnoreCC ExactTypeDescValues ExactGenericParams @@ -673,7 +677,7 @@ type proc initSameTypeClosure: TSameTypeClosure = # we do the initialization lazily for performance (avoids memory allocations) discard - + proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = result = not isNil(c.s) and c.s.contains((a.id, b.id)) if not result: @@ -700,17 +704,17 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool = if a == nil or b == nil: result = false else: result = sameType(a, b, flags) -proc equalParam(a, b: PSym): TParamsEquality = +proc equalParam(a, b: PSym): TParamsEquality = if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and exprStructuralEquivalent(a.constraint, b.constraint): - if a.ast == b.ast: + if a.ast == b.ast: result = paramsEqual - elif a.ast != nil and b.ast != nil: + elif a.ast != nil and b.ast != nil: if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual else: result = paramsIncompatible - elif a.ast != nil: + elif a.ast != nil: result = paramsEqual - elif b.ast != nil: + elif b.ast != nil: result = paramsIncompatible else: result = paramsNotEqual @@ -723,70 +727,70 @@ proc sameConstraints(a, b: PNode): bool = return false return true -proc equalParams(a, b: PNode): TParamsEquality = +proc equalParams(a, b: PNode): TParamsEquality = result = paramsEqual var length = sonsLen(a) - if length != sonsLen(b): + if length != sonsLen(b): result = paramsNotEqual - else: - for i in countup(1, length - 1): + else: + for i in countup(1, length - 1): var m = a.sons[i].sym var n = b.sons[i].sym assert((m.kind == skParam) and (n.kind == skParam)) case equalParam(m, n) - of paramsNotEqual: + of paramsNotEqual: return paramsNotEqual - of paramsEqual: + of paramsEqual: discard - of paramsIncompatible: + of paramsIncompatible: result = paramsIncompatible - if (m.name.id != n.name.id): + if (m.name.id != n.name.id): # BUGFIX return paramsNotEqual # paramsIncompatible; # continue traversal! If not equal, we can return immediately; else # it stays incompatible if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}): - if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): + if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): result = paramsNotEqual # one proc has a result, the other not is OK - else: + else: result = paramsIncompatible # overloading by different # result types does not work - -proc sameLiteral(x, y: PNode): bool = - if x.kind == y.kind: + +proc sameLiteral(x, y: PNode): bool = + if x.kind == y.kind: case x.kind of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal of nkNilLit: result = true else: assert(false) - -proc sameRanges(a, b: PNode): bool = + +proc sameRanges(a, b: PNode): bool = result = sameLiteral(a.sons[0], b.sons[0]) and sameLiteral(a.sons[1], b.sons[1]) -proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = +proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = # two tuples are equivalent iff the names, types and positions are the same; # however, both types may not have any field names (t.n may be nil) which # complicates the matter a bit. if sonsLen(a) == sonsLen(b): result = true - for i in countup(0, sonsLen(a) - 1): + for i in countup(0, sonsLen(a) - 1): var x = a.sons[i] var y = b.sons[i] if IgnoreTupleFields in c.flags: - x = skipTypes(x, {tyRange}) - y = skipTypes(y, {tyRange}) - + x = skipTypes(x, {tyRange, tyGenericInst}) + y = skipTypes(y, {tyRange, tyGenericInst}) + result = sameTypeAux(x, y, c) - if not result: return + if not result: return if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags: - for i in countup(0, sonsLen(a.n) - 1): - # check field names: + for i in countup(0, sonsLen(a.n) - 1): + # check field names: if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym: var x = a.n.sons[i].sym var y = b.n.sons[i].sym result = x.name.id == y.name.id - if not result: break + if not result: break else: internalError(a.n.info, "sameTuple") template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = @@ -797,7 +801,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = # expensive structural equality test; however due to the way generic and # objects work, if one of the types does **not** contain tfFromGeneric, # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks - # for the same origin and is essential because we don't want "pure" + # for the same origin and is essential because we don't want "pure" # structural type equivalence: # # type @@ -823,8 +827,13 @@ proc sameEnumTypes*(a, b: PType): bool {.inline.} = proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool = if a == b: result = true - elif (a != nil) and (b != nil) and (a.kind == b.kind): - if sameTypeOrNilAux(a.typ, b.typ, c): + elif a != nil and b != nil and a.kind == b.kind: + var x = a.typ + var y = b.typ + if IgnoreTupleFields in c.flags: + if x != nil: x = skipTypes(x, {tyRange, tyGenericInst}) + if y != nil: y = skipTypes(y, {tyRange, tyGenericInst}) + if sameTypeOrNilAux(x, y, c): case a.kind of nkSym: # same symbol as string is enough: @@ -835,9 +844,9 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool = of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true else: - if sonsLen(a) == sonsLen(b): - for i in countup(0, sonsLen(a) - 1): - if not sameObjectTree(a.sons[i], b.sons[i], c): return + if sonsLen(a) == sonsLen(b): + for i in countup(0, sonsLen(a) - 1): + if not sameObjectTree(a.sons[i], b.sons[i], c): return result = true proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool = @@ -853,7 +862,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = result = true for i in countup(0, sonsLen(a) - 1): result = sameTypeOrNilAux(a.sons[i], b.sons[i], c) - if not result: return + if not result: return proc isGenericAlias*(t: PType): bool = return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst @@ -866,7 +875,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = # believe it or not, the direct check for ``containsOrIncl(c, a, b)`` # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat # again: Since the recursion check is only to not get caught in an endless - # recursion, we use a counter and only if it's value is over some + # recursion, we use a counter and only if it's value is over some # threshold we perform the expensive exact cycle check: if c.recCheck < 3: inc c.recCheck @@ -874,11 +883,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if containsOrIncl(c, a, b): return true proc sameFlags(a, b: PType): bool {.inline.} = - result = eqTypeFlags*a.flags == eqTypeFlags*b.flags + result = eqTypeFlags*a.flags == eqTypeFlags*b.flags if x == y: return true var a = skipTypes(x, {tyGenericInst}) - var b = skipTypes(y, {tyGenericInst}) + var b = skipTypes(y, {tyGenericInst}) assert(a != nil) assert(b != nil) if a.kind != b.kind: @@ -891,7 +900,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of dcEqOrDistinctOf: while a.kind == tyDistinct: a = a.sons[0] if a.kind != b.kind: return false - + if x.kind == tyGenericInst: let lhs = x.skipGenericAlias @@ -916,11 +925,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameObjectStructures(a, b, c) and sameFlags(a, b) of tyDistinct: cycleCheck() - if c.cmp == dcEq: + if c.cmp == dcEq: if sameFlags(a, b): ifFastObjectTypeCheckFailed(a, b): - result = sameTypeAux(a.sons[0], b.sons[0], c) - else: + result = sameTypeAux(a.sons[0], b.sons[0], c) + else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) of tyEnum, tyForward: # XXX generic enums do not make much sense, but require structural checking @@ -957,13 +966,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = sameValue(a.n.sons[0], b.n.sons[0]) and sameValue(a.n.sons[1], b.n.sons[1]) of tyGenericInst: discard - of tyNone: result = false + of tyNone: result = false proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() c.flags.incl IgnoreTupleFields result = sameTypeAux(x, y, c) - + proc compareTypes*(x, y: PType, cmp: TDistinctCompare = dcEq, flags: TTypeCmpFlags = {}): bool = @@ -972,8 +981,8 @@ proc compareTypes*(x, y: PType, c.cmp = cmp c.flags = flags result = sameTypeAux(x, y, c) - -proc inheritanceDiff*(a, b: PType): int = + +proc inheritanceDiff*(a, b: PType): int = # | returns: 0 iff `a` == `b` # | returns: -x iff `a` is the x'th direct superclass of `b` # | returns: +x iff `a` is the x'th direct subclass of `b` @@ -985,14 +994,14 @@ proc inheritanceDiff*(a, b: PType): int = result = 0 while x != nil: x = skipTypes(x, skipPtrs) - if sameObjectTypes(x, b): return + if sameObjectTypes(x, b): return x = x.sons[0] dec(result) var y = b result = 0 while y != nil: y = skipTypes(y, skipPtrs) - if sameObjectTypes(y, a): return + if sameObjectTypes(y, a): return y = y.sons[0] inc(result) result = high(int) @@ -1066,7 +1075,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind == skConst: return t var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}) case t2.kind - of tyVar: + of tyVar: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap of tyOpenArray: if kind != skParam: result = t @@ -1075,9 +1084,9 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind notin {skParam, skResult}: result = t else: result = typeAllowedAux(marker, t2, kind, flags) of tyProc: - for i in countup(1, sonsLen(t) - 1): + for i in countup(1, sonsLen(t) - 1): result = typeAllowedAux(marker, t.sons[i], skParam, flags) - if result != nil: break + if result != nil: break if result.isNil and t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult, flags) of tyExpr, tyStmt, tyTypeDesc, tyStatic: @@ -1092,7 +1101,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t of tyNil: if kind != skConst: result = t - of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: + of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: result = nil of tyOrdinal: if kind != skParam: result = t @@ -1132,13 +1141,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, # prevent cascading errors: result = nil -proc typeAllowed*(t: PType, kind: TSymKind): PType = +proc typeAllowed*(t: PType, kind: TSymKind): PType = # returns 'nil' on success and otherwise the part of the type that is # wrong! var marker = initIntSet() result = typeAllowedAux(marker, t, kind, {}) -proc align(address, alignment: BiggestInt): BiggestInt = +proc align(address, alignment: BiggestInt): BiggestInt = result = (address + (alignment - 1)) and not (alignment - 1) const @@ -1147,17 +1156,17 @@ const szUnknownSize* = -1 proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt -proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = +proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = var maxAlign, maxSize, b, res: BiggestInt case n.kind - of nkRecCase: + of nkRecCase: assert(n.sons[0].kind == nkSym) result = computeRecSizeAux(n.sons[0], a, currOffset) maxSize = 0 maxAlign = 1 - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkOfBranch, nkElse: + of nkOfBranch, nkElse: res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset) if res < 0: return res maxSize = max(maxSize, res) @@ -1166,17 +1175,17 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = currOffset = align(currOffset, maxAlign) + maxSize result = align(result, maxAlign) + maxSize a = maxAlign - of nkRecList: + of nkRecList: result = 0 maxAlign = 1 - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): res = computeRecSizeAux(n.sons[i], b, currOffset) if res < 0: return res currOffset = align(currOffset, b) + res result = align(result, b) + res if b > maxAlign: maxAlign = b a = maxAlign - of nkSym: + of nkSym: result = computeSizeAux(n.sym.typ, a) n.sym.offset = int(currOffset) else: @@ -1193,31 +1202,31 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = # size already computed result = typ.size a = typ.align - return + return typ.size = szIllegalRecursion # mark as being computed case typ.kind - of tyInt, tyUInt: + of tyInt, tyUInt: result = intSize a = result - of tyInt8, tyUInt8, tyBool, tyChar: + of tyInt8, tyUInt8, tyBool, tyChar: result = 1 a = result - of tyInt16, tyUInt16: + of tyInt16, tyUInt16: result = 2 a = result - of tyInt32, tyUInt32, tyFloat32: + of tyInt32, tyUInt32, tyFloat32: result = 4 a = result - of tyInt64, tyUInt64, tyFloat64: + of tyInt64, tyUInt64, tyFloat64: result = 8 a = result of tyFloat128: result = 16 a = result - of tyFloat: + of tyFloat: result = floatSize a = result - of tyProc: + of tyProc: if typ.callConv == ccClosure: result = 2 * ptrSize else: result = ptrSize a = ptrSize @@ -1232,17 +1241,17 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = let elemSize = computeSizeAux(typ.sons[1], a) if elemSize < 0: return elemSize result = lengthOrd(typ.sons[0]) * elemSize - of tyEnum: - if firstOrd(typ) < 0: + of tyEnum: + if firstOrd(typ) < 0: result = 4 # use signed int32 - else: + else: length = lastOrd(typ) # BUGFIX: use lastOrd! if length + 1 < `shl`(1, 8): result = 1 elif length + 1 < `shl`(1, 16): result = 2 elif length + 1 < `shl`(BiggestInt(1), 32): result = 4 else: result = 8 a = result - of tySet: + of tySet: length = lengthOrd(typ.sons[0]) if length <= 8: result = 1 elif length <= 16: result = 2 @@ -1251,32 +1260,32 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8 else: result = align(length, 8) div 8 + 1 a = result - of tyRange: + of tyRange: result = computeSizeAux(typ.sons[0], a) - of tyTuple: + of tyTuple: result = 0 maxAlign = 1 - for i in countup(0, sonsLen(typ) - 1): + for i in countup(0, sonsLen(typ) - 1): res = computeSizeAux(typ.sons[i], a) if res < 0: return res maxAlign = max(maxAlign, a) result = align(result, a) + res result = align(result, maxAlign) a = maxAlign - of tyObject: - if typ.sons[0] != nil: + of tyObject: + if typ.sons[0] != nil: result = computeSizeAux(typ.sons[0], a) - if result < 0: return + if result < 0: return maxAlign = a - elif isObjectWithTypeFieldPredicate(typ): + elif isObjectWithTypeFieldPredicate(typ): result = intSize maxAlign = result - else: + else: result = 0 maxAlign = 1 currOffset = result result = computeRecSizeAux(typ.n, a, currOffset) - if result < 0: return + if result < 0: return if a < maxAlign: a = maxAlign result = align(result, a) of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter: @@ -1290,7 +1299,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = typ.size = result typ.align = int16(a) -proc computeSize(typ: PType): BiggestInt = +proc computeSize(typ: PType): BiggestInt = var a: BiggestInt = 1 result = computeSizeAux(typ, a) @@ -1299,7 +1308,7 @@ proc getReturnType*(s: PSym): PType = assert s.kind in skProcKinds result = s.typ.sons[0] -proc getSize(typ: PType): BiggestInt = +proc getSize(typ: PType): BiggestInt = result = computeSize(typ) if result < 0: internalError("getSize: " & $typ.kind) @@ -1317,7 +1326,7 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool = return false -proc containsGenericType*(t: PType): bool = +proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) proc baseOfDistinct*(t: PType): PType = @@ -1336,7 +1345,7 @@ proc baseOfDistinct*(t: PType): PType = proc safeInheritanceDiff*(a, b: PType): int = # same as inheritanceDiff but checks for tyError: - if a.kind == tyError or b.kind == tyError: + if a.kind == tyError or b.kind == tyError: result = -1 else: result = inheritanceDiff(a, b) @@ -1356,7 +1365,7 @@ proc compatibleEffects*(formal, actual: PType): bool = assert formal.kind == tyProc and actual.kind == tyProc internalAssert formal.n.sons[0].kind == nkEffectList internalAssert actual.n.sons[0].kind == nkEffectList - + var spec = formal.n.sons[0] if spec.len != 0: var real = actual.n.sons[0] diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 995fe7f50..700356ab7 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -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)] = ']' diff --git a/compiler/vm.nim b/compiler/vm.nim index e96b89f49..f0a0135e8 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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] @@ -776,10 +776,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = stackTrace(c, tos, pc, errNilAccess) of opcEcho: let rb = instr.regB - for i in ra..ra+rb-1: - #if regs[i].kind != rkNode: debug regs[i] - write(stdout, regs[i].node.strVal) - writeln(stdout, "") + if rb == 1: + msgWriteln(regs[ra].node.strVal) + else: + var outp = "" + for i in ra..ra+rb-1: + #if regs[i].kind != rkNode: debug regs[i] + outp.add(regs[i].node.strVal) + msgWriteln(outp) of opcContainsSet: decodeBC(rkInt) regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) @@ -789,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) @@ -892,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: @@ -1269,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: @@ -1277,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) @@ -1305,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: @@ -1431,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 = @@ -1492,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 diff --git a/doc/advopt.txt b/doc/advopt.txt index 7b3695532..d4b1b7e57 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -48,7 +48,6 @@ Advanced options: --os:SYMBOL set the target operating system (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation) --debuginfo enables debug information - --debugger:on|off turn Embedded Nim Debugger on|off -t, --passC:OPTION pass an option to the C compiler -l, --passL:OPTION pass an option to the linker --cincludes:DIR modify the C compiler header search path @@ -88,7 +87,5 @@ Advanced options: --parallelBuild:0|1|... perform a parallel build value = number of processors (0 for auto-detect) --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) - --cs:none|partial set case sensitivity level (default: none); - do not use! this setting affects the whole language --experimental enable experimental language features -v, --version show detailed version information diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 27b10badc..7d08f1159 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -6,7 +6,6 @@ Command: //compile, c compile project with default code generator (C) //doc generate the documentation for inputfile //doc2 generate the documentation for the whole project - //i start Nim in interactive mode (limited) Arguments: arguments are passed to the program being run (if --run option is selected) @@ -30,6 +29,7 @@ Options: --infChecks:on|off turn Inf checks on|off --deadCodeElim:on|off whole program dead code elimination on|off --opt:none|speed|size optimize not at all or for speed|size + --debugger:native|endb use native debugger (gdb) | ENDB (experimental) --app:console|gui|lib|staticlib generate a console app|GUI app|DLL|static library -r, --run run the compiled program with given arguments diff --git a/doc/lib.txt b/doc/lib.txt index 76920c6a9..385e7a91a 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -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 -------------- diff --git a/koch.nim b/koch.nim index d365262c1..34cb1317d 100644 --- a/koch.nim +++ b/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() diff --git a/lib/core/macros.nim b/lib/core/macros.nim index dbfb2ceb3..f73dbd241 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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, @@ -456,10 +456,11 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} = of nnkSym: add(result, $n.symbol) of nnkNone: assert false else: - add(result, lispRepr(n[0])) - for j in 1..n.len-1: - add(result, ", ") - add(result, lispRepr(n[j])) + if n.len > 0: + add(result, lispRepr(n[0])) + for j in 1..n.len-1: + add(result, ", ") + add(result, lispRepr(n[j])) add(result, ")") @@ -580,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.} = @@ -653,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: @@ -775,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. diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 0046924a1..c3ff66591 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -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)) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 7d5ff8948..921a24fd1 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -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: ## diff --git a/lib/nimbase.h b/lib/nimbase.h index af21c8945..e9dad0bb7 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -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 diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 95d49bad7..97784898e 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -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) diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 52af672df..614001d76 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -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) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index e1e590877..a385336d6 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -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: diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 20bfc5c7c..20976e788 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -187,6 +187,34 @@ 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. diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index d6ed66030..bf905ed49 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -121,7 +121,7 @@ export Port, SocketFlag ## ## Limitations/Bugs ## ---------------- -## +## ## * ``except`` statement (without `try`) does not work inside async procedures. ## * The effect system (``raises: []``) does not work with async procedures. ## * Can't await in a ``except`` body @@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc): if p.handles.len == 0 and p.timers.len == 0: raise newException(ValueError, "No handles or timers registered in dispatcher.") - + let llTimeout = if timeout == -1: winlean.INFINITE else: timeout.int32 @@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc): if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS): raiseOSError(osLastError()) - proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, + proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: Dword, lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool = if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().") let fun = - cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, + cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: Dword, lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr) @@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc): dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr) - + fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength, RemoteSockaddr, RemoteSockaddrLength) @@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc): else: retFuture.fail(newException(OSError, osErrorMsg(errcode))) ) - + var ret = connectEx(socket.SocketHandle, it.ai_addr, sizeof(Sockaddr_in).cint, nil, 0, nil, cast[POVERLAPPED](ol)) @@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc): var dataBuf: TWSABuf dataBuf.buf = cast[cstring](alloc0(size)) dataBuf.len = size - + var bytesReceived: Dword var flagsio = flags.toOSFlags().Dword var ol = PCustomOverlapped() @@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc): # the empty string (which signals a disconnection) when there is # nothing left to read. retFuture.complete("") - # TODO: "For message-oriented sockets, where a zero byte message is often - # allowable, a failure with an error code of WSAEDISCON is used to - # indicate graceful closure." + # TODO: "For message-oriented sockets, where a zero byte message is often + # allowable, a failure with an error code of WSAEDISCON is used to + # indicate graceful closure." # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx else: # Request to read completed immediately. @@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc): # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0], - dwReceiveDataLength, + dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, addr dwBytesReceived, cast[POVERLAPPED](ol)) @@ -803,7 +803,7 @@ else: else: from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, MSG_NOSIGNAL - + type TAsyncFD* = distinct cint TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.} @@ -849,7 +849,7 @@ else: result = newRawSocket(domain, typ, protocol).TAsyncFD result.SocketHandle.setBlocking(false) register(result) - + proc closeSocket*(sock: TAsyncFD) = let disp = getGlobalDispatcher() sock.SocketHandle.close() @@ -864,14 +864,14 @@ else: raise newException(ValueError, "File descriptor not registered.") p.selector[fd.SocketHandle].data.PData.readCBs.add(cb) update(fd, p.selector[fd.SocketHandle].events + {EvRead}) - + proc addWrite*(fd: TAsyncFD, cb: TCallback) = let p = getGlobalDispatcher() if fd.SocketHandle notin p.selector: raise newException(ValueError, "File descriptor not registered.") p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb) update(fd, p.selector[fd.SocketHandle].events + {EvWrite}) - + proc poll*(timeout = 500) = let p = getGlobalDispatcher() for info in p.selector.select(timeout): @@ -892,7 +892,7 @@ else: if not cb(data.fd): # Callback wants to be called again. data.readCBs.add(cb) - + if EvWrite in info.events: let currentCBs = data.writeCBs data.writeCBs = @[] @@ -900,7 +900,7 @@ else: if not cb(data.fd): # Callback wants to be called again. data.writeCBs.add(cb) - + if info.key in p.selector: var newEvents: set[Event] if data.readCBs.len != 0: newEvents = {EvRead} @@ -913,16 +913,16 @@ else: discard processTimers(p) - + proc connect*(socket: TAsyncFD, address: string, port: Port, af = AF_INET): Future[void] = var retFuture = newFuture[void]("connect") - + proc cb(fd: TAsyncFD): bool = # We have connected. retFuture.complete() return true - + var aiList = getAddrInfo(address, port, af) var success = false var lastError: OSErrorCode @@ -952,7 +952,7 @@ else: proc recv*(socket: TAsyncFD, size: int, flags = {SocketFlag.SafeDisconn}): Future[string] = var retFuture = newFuture[string]("recv") - + var readBuffer = newString(size) proc cb(sock: TAsyncFD): bool = @@ -983,9 +983,9 @@ else: proc send*(socket: TAsyncFD, data: string, flags = {SocketFlag.SafeDisconn}): Future[void] = var retFuture = newFuture[void]("send") - + var written = 0 - + proc cb(sock: TAsyncFD): bool = result = true let netSize = data.len-written @@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode, of nnkTryStmt: # try: await x; except: ... result = newNimNode(nnkStmtList, node) - template wrapInTry(n, tryBody: PNimrodNode) = + template wrapInTry(n, tryBody: expr) = var temp = n n[0] = tryBody tryBody = temp @@ -1315,14 +1315,14 @@ macro async*(prc: stmt): stmt {.immediate.} = if returnType.kind == nnkEmpty: newIdentNode("void") else: returnType[1] outerProcBody.add( - newVarStmt(retFutureSym, + newVarStmt(retFutureSym, newCall( newNimNode(nnkBracketExpr, prc[6]).add( newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`. subRetType), newLit(prc[0].getName)))) # Get type from return type of this proc - - # -> iterator nameIter(): FutureBase {.closure.} = + + # -> iterator nameIter(): FutureBase {.closure.} = # -> var result: T # -> <proc_body> # -> complete(retFuture, result) @@ -1337,7 +1337,7 @@ macro async*(prc: stmt): stmt {.immediate.} = else: # -> complete(retFuture) procBody.add(newCall(newIdentNode("complete"), retFutureSym)) - + var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], procBody, nnkIteratorDef) closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) @@ -1351,7 +1351,7 @@ macro async*(prc: stmt): stmt {.immediate.} = # -> return retFuture outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym) - + result = prc # Remove the 'async' pragma. @@ -1377,7 +1377,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = ## If a full line is read ``\r\L`` is not ## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## will be set to it. - ## + ## ## If the socket is disconnected, ``line`` will be set to ``""``. ## ## If the socket is disconnected in the middle of a line (before ``\r\L`` @@ -1388,7 +1388,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = ## ## **Note**: This procedure is mostly used for testing. You likely want to ## use ``asyncnet.recvLine`` instead. - + template addNLIfEmpty(): stmt = if result.len == 0: result.add("\c\L") diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 752c01eac..844c2ab55 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -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 @@ -30,7 +30,7 @@ else: import posix type - AsyncFile = ref object + AsyncFile* = ref object fd: TAsyncFd offset: int64 diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e690e8eba..edb904cc6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -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" diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 959688d6a..93a7591ac 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -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`. diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 9f1546eed..8577bf7a1 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -274,27 +274,86 @@ proc tan*(z: Complex): Complex = ## Returns the tangent of `z`. result = sin(z)/cos(z) +proc arctan*(z: Complex): Complex = + ## Returns the inverse tangent of `z`. + var i: Complex = (0.0,1.0) + result = 0.5*i*(ln(1-i*z)-ln(1+i*z)) + proc cot*(z: Complex): Complex = ## Returns the cotangent of `z`. result = cos(z)/sin(z) +proc arccot*(z: Complex): Complex = + ## Returns the inverse cotangent of `z`. + var i: Complex = (0.0,1.0) + result = 0.5*i*(ln(1-i/z)-ln(1+i/z)) + proc sec*(z: Complex): Complex = ## Returns the secant of `z`. result = 1.0/cos(z) +proc arcsec*(z: Complex): Complex = + ## Returns the inverse secant of `z`. + var i: Complex = (0.0,1.0) + result = -i*ln(i*sqrt(1-1/(z*z))+1/z) + proc csc*(z: Complex): Complex = ## Returns the cosecant of `z`. result = 1.0/sin(z) +proc arccsc*(z: Complex): Complex = + ## Returns the inverse cosecant of `z`. + var i: Complex = (0.0,1.0) + result = -i*ln(sqrt(1-1/(z*z))+i/z) + proc sinh*(z: Complex): Complex = ## Returns the hyperbolic sine of `z`. result = 0.5*(exp(z)-exp(-z)) +proc arcsinh*(z: Complex): Complex = + ## Returns the inverse hyperbolic sine of `z`. + result = ln(z+sqrt(z*z+1)) + proc cosh*(z: Complex): Complex = ## Returns the hyperbolic cosine of `z`. result = 0.5*(exp(z)+exp(-z)) +proc arccosh*(z: Complex): Complex = + ## Returns the inverse hyperbolic cosine of `z`. + result = ln(z+sqrt(z*z-1)) + +proc tanh*(z: Complex): Complex = + ## Returns the hyperbolic tangent of `z`. + result = sinh(z)/cosh(z) + +proc arctanh*(z: Complex): Complex = + ## Returns the inverse hyperbolic tangent of `z`. + result = 0.5*(ln((1+z)/(1-z))) + +proc sech*(z: Complex): Complex = + ## Returns the hyperbolic secant of `z`. + result = 2/(exp(z)+exp(-z)) + +proc arcsech*(z: Complex): Complex = + ## Returns the inverse hyperbolic secant of `z`. + result = ln(1/z+sqrt(1/z+1)*sqrt(1/z-1)) + +proc csch*(z: Complex): Complex = + ## Returns the hyperbolic cosecant of `z`. + result = 2/(exp(z)-exp(-z)) + +proc arccsch*(z: Complex): Complex = + ## Returns the inverse hyperbolic cosecant of `z`. + result = ln(1/z+sqrt(1/(z*z)+1)) + +proc coth*(z: Complex): Complex = + ## Returns the hyperbolic cotangent of `z`. + result = cosh(z)/sinh(z) + +proc arccoth*(z: Complex): Complex = + ## Returns the inverse hyperbolic cotangent of `z`. + result = 0.5*(ln(1+1/z)-ln(1-1/z)) proc phase*(z: Complex): float = ## Returns the phase of `z`. @@ -306,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 = @@ -363,10 +422,22 @@ when isMainModule: assert( csc(a) =~ 1.0/sin(a) ) assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) ) assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) ) + assert( arctan(a) =~ (1.338972522294494, 0.402359478108525) ) assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) ) + assert( tanh(a) =~ (1.1667362572409199,-0.243458201185725) ) + assert( sech(a) =~ 1/cosh(a) ) + assert( csch(a) =~ 1/sinh(a) ) + assert( coth(a) =~ 1/tanh(a) ) + assert( arccosh(a) =~ (1.528570919480998, 1.14371774040242) ) + assert( arcsinh(a) =~ (1.469351744368185, 1.06344002357775) ) + assert( arctanh(a) =~ (0.173286795139986, 1.17809724509617) ) + assert( arcsech(a) =~ arccosh(1/a) ) + assert( arccsch(a) =~ arcsinh(1/a) ) + 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) ) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 30daaf2dc..a16342d44 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -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 diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 37af14df3..f11101511 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -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") diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 2038b246d..5041fe2f6 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -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 diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index a3a3d7b5c..23a87d9f8 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -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") diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index b1e2444c3..4c92a7cdf 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -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" diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index b957c0cf7..b8f422c31 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string, my.kind = xmlError my.a = "" my.b = "" + my.c = "" 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. @@ -446,13 +447,15 @@ proc parseTag(my: var XmlParser) = # an attribute follows: my.kind = xmlElementOpen my.state = stateAttr - my.c = my.a # save for later + # save for later: + my.c.setLen(my.a.len) + my.c[0..my.c.high] = my.a[0..my.a.high] else: my.kind = xmlElementStart if my.buf[my.bufpos] == '/' and my.buf[my.bufpos+1] == '>': inc(my.bufpos, 2) my.state = stateEmptyElementTag - my.c = nil + my.c.setLen(0) elif my.buf[my.bufpos] == '>': inc(my.bufpos) else: @@ -621,8 +624,9 @@ proc next*(my: var XmlParser) = of stateEmptyElementTag: my.state = stateNormal my.kind = xmlElementEnd - if not isNil(my.c): - my.a = my.c + if my.c.len > 0: + my.a.setLen(my.c.len) + my.a[0..my.a.high] = my.c[0..my.c.high] of stateError: my.kind = xmlError my.state = stateNormal diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 419554de5..04c75ecae 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -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.} = + +proc unicodeLower*: Peg {.inline.} = ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. - result.kind = pkLower + result.kind = pkLower -proc unicodeUpper*: Peg {.inline.} = +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*)+") diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index 40c61f1d9..04aa8316a 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -22,6 +22,16 @@ proc initRational*[T](num, den: T): Rational[T] = result.num = num result.den = den +proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den) + ## A friendlier version of `initRational`. Example usage: + ## + ## .. code-block:: nim + ## var x = 1//3 + 1//5 + +proc `$`*[T](x: Rational[T]): string = + ## Turn a rational number into a string. + result = $x.num & "/" & $x.den + proc toRational*[T](x: SomeInteger): Rational[T] = ## Convert some integer `x` to a rational number. result.num = x @@ -200,26 +210,26 @@ when isMainModule: z = Rational[int](num: 0, den: 1) o = initRational(num=1, den=1) a = initRational(1, 2) - b = initRational(-1, -2) - m1 = initRational(-1, 1) - tt = initRational(10, 2) + b = -1 // -2 + m1 = -1 // 1 + tt = 10 // 2 assert( a == a ) assert( (a-a) == z ) assert( (a+b) == o ) assert( (a/b) == o ) - assert( (a*b) == initRational(1, 4) ) - assert( (3/a) == initRational(6,1) ) - assert( (a/3) == initRational(1,6) ) - assert( a*b == initRational(1,4) ) + assert( (a*b) == 1 // 4 ) + assert( (3/a) == 6 // 1 ) + assert( (a/3) == 1 // 6 ) + assert( a*b == 1 // 4 ) assert( tt*z == z ) assert( 10*a == tt ) assert( a*10 == tt ) assert( tt/10 == a ) - assert( a-m1 == initRational(3, 2) ) - assert( a+m1 == initRational(-1, 2) ) - assert( m1+tt == initRational(16, 4) ) - assert( m1-tt == initRational(6, -1) ) + assert( a-m1 == 3 // 2 ) + assert( a+m1 == -1 // 2 ) + assert( m1+tt == 16 // 4 ) + assert( m1-tt == 6 // -1 ) assert( z < o ) assert( z <= o ) @@ -238,28 +248,28 @@ when isMainModule: assert( not(b > a) ) assert( cmp(a, b) == 0 ) - var x = initRational(1,3) + var x = 1//3 - x *= initRational(5,1) - assert( x == initRational(5,3) ) - x += initRational(2,9) - assert( x == initRational(17,9) ) - x -= initRational(9,18) - assert( x == initRational(25,18) ) - x /= initRational(1,2) - assert( x == initRational(50,18) ) + x *= 5//1 + assert( x == 5//3 ) + x += 2 // 9 + assert( x == 17//9 ) + x -= 9//18 + assert( x == 25//18 ) + x /= 1//2 + assert( x == 50//18 ) - var y = initRational(1,3) + var y = 1//3 y *= 4 - assert( y == initRational(4,3) ) + assert( y == 4//3 ) y += 5 - assert( y == initRational(19,3) ) + assert( y == 19//3 ) y -= 2 - assert( y == initRational(13,3) ) + assert( y == 13//3 ) y /= 9 - assert( y == initRational(13,27) ) + assert( y == 13//27 ) - assert toRational[int, int](5) == initRational(5,1) + assert toRational[int, int](5) == 5//1 assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 assert toInt(z) == 0 diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim index 52d81b3a4..64d3e1470 100644 --- a/lib/pure/redis.nim +++ b/lib/pure/redis.nim @@ -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 diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 67c80e592..e706f2016 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -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) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 39f468ee3..655203cda 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -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".} = diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e32ea786a..c39667611 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -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 diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 42e6a3195..a6f8f916b 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -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 diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 9a6e273a8..b0afb75f9 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -286,6 +286,16 @@ proc `$`*(u: Uri): string = 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) doAssert test.scheme == "http" diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 2e55ff182..6242e589e 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -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 diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 7a26a17c5..093c0f3a7 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -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 diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 1f4279c8f..9de0c6503 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -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.} = diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index ae2d2c85d..b8a61d627 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -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") diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 7dee054ac..aff0c0e6f 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -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] diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index a05398a09..48adb895d 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -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 diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 9d9cc0070..11780a9aa 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -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](rawNewObj(addr(strDesc), size, gch)) + +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.} = @@ -264,7 +276,17 @@ proc nimFloatToStr(f: float): string {.compilerproc.} = 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.} diff --git a/readme.md b/readme.md index 2252ea52b..e716c0d0d 100644 --- a/readme.md +++ b/readme.md @@ -39,8 +39,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 diff --git a/tests/actiontable/tactiontable2.nim b/tests/actiontable/tactiontable2.nim index 99bb3dca0..fbc65a67d 100644 --- a/tests/actiontable/tactiontable2.nim +++ b/tests/actiontable/tactiontable2.nim @@ -1,6 +1,5 @@ discard """ - line: 21 - errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'" + output: "action 3 arg" """ import tables diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim index 8766321bf..16769f529 100644 --- a/tests/assert/tfailedassert.nim +++ b/tests/assert/tfailedassert.nim @@ -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 diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim new file mode 100644 index 000000000..edff1dd4e --- /dev/null +++ b/tests/ccgbugs/tmissingderef.nim @@ -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() diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim new file mode 100644 index 000000000..50c363a4a --- /dev/null +++ b/tests/ccgbugs/trecursive_closure.nim @@ -0,0 +1,8 @@ +# bug #2233 +type MalType = object + fun: proc: MalType + +proc f(x: proc: MalType) = + discard x() + +f(nil) diff --git a/tests/ccgbugs/tstringslice.nim b/tests/ccgbugs/tstringslice.nim new file mode 100644 index 000000000..66b3bbbe4 --- /dev/null +++ b/tests/ccgbugs/tstringslice.nim @@ -0,0 +1,10 @@ + +# 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 diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim new file mode 100644 index 000000000..960e2aae9 --- /dev/null +++ b/tests/ccgbugs/tuple_canon.nim @@ -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() diff --git a/tests/clearmsg/tconsttypemismatch.nim b/tests/clearmsg/tconsttypemismatch.nim new file mode 100644 index 000000000..edf480348 --- /dev/null +++ b/tests/clearmsg/tconsttypemismatch.nim @@ -0,0 +1,8 @@ +discard """ + file: "tconsttypemismatch.nim" + line: 7 + errormsg: "type mismatch" +""" +# bug #2252 +const foo: int = 1000 / 30 + diff --git a/tests/cpp/trawsockets.nim b/tests/cpp/trawsockets.nim index d034245d0..bc129de57 100644 --- a/tests/cpp/trawsockets.nim +++ b/tests/cpp/trawsockets.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim cpp $target" + cmd: "nim cpp $file" """ import rawsockets diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo.nim index e72883dbf..1529c86e9 100644 --- a/tests/cpp/ttypeinfo.nim +++ b/tests/cpp/ttypeinfo.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim cpp $target" + cmd: "nim cpp $file" """ import typeinfo diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim index f41f0a72f..ed3d2733a 100644 --- a/tests/deprecated/tdeprecated.nim +++ b/tests/deprecated/tdeprecated.nim @@ -1,6 +1,5 @@ discard """ - line: 9 - errormsg: "'a' is deprecated [Deprecated]" + nimout: "'a' is deprecated [Deprecated]" """ var @@ -8,4 +7,3 @@ var a[8] = 1 - diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim index 1bdf4993b..6f966d861 100644 --- a/tests/destructor/tdestructor2.nim +++ b/tests/destructor/tdestructor2.nim @@ -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() diff --git a/tests/exception/tdefer1.nim b/tests/exception/tdefer1.nim new file mode 100644 index 000000000..61439530a --- /dev/null +++ b/tests/exception/tdefer1.nim @@ -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" diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index 6fb929efb..289bf1fd5 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -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: diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim new file mode 100644 index 000000000..2db8b4353 --- /dev/null +++ b/tests/generics/twrong_floatlit_type.nim @@ -0,0 +1,118 @@ +discard """ + errormsg: "type mismatch" + line: 116 +""" + +# bug #2169 +import strutils, math + +type + Point2D*[S] = object + x*, y*: S + Matrix2x3*[S] = distinct array[6, S] ## Row major order + + Vector2D*[S] = object + x*, y*: S + +proc `[]`*[T](m: Matrix2x3[T], i: int): T = array[6, T](m)[i] + +template M11*[T](m: Matrix2x3[T]): T = m[0] +template M12*[T](m: Matrix2x3[T]): T = m[1] +template M13*[T](m: Matrix2x3[T]): T = m[2] +template M21*[T](m: Matrix2x3[T]): T = m[3] +template M22*[T](m: Matrix2x3[T]): T = m[4] +template M23*[T](m: Matrix2x3[T]): T = m[5] + +proc identity*[T](): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), 0.0, 0.0, 0.0, 1.0, 0.0]) + +proc translation*[T](p: Point2D[T]): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y]) + +proc translation*[T](p: Vector2D[T]): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y]) + +proc scale*[T](v: Vector2D[T]): Matrix2x3[T] = + Matrix2x3[T]([v.x, T(0.0), T(0.0), T(0.0), v.y, T(0.0)]) + +proc rotation*[T](th: T): Matrix2x3[T] = + let + c = T(cos(th.float)) + s = T(sin(th.float)) + + Matrix2x3[T]([c, -s, T(0.0), s, c, T(0.0)]) + +proc `*`*[T](a, b: Matrix2x3[T]): Matrix2x3[T] = + # Here we pretend that row 3 is [0,0,0,1] without + # actually storing it in the matrix. + Matrix2x3[T]([a.M11*b.M11 + a.M12*b.M21, + a.M11*b.M12 + a.M12*b.M22, + a.M11*b.M13 + a.M12*b.M23 + a.M13, + + a.M21*b.M11 + a.M22*b.M21, + a.M21*b.M12 + a.M22*b.M22, + a.M21*b.M13 + a.M22*b.M23 + a.M23]) + +proc `*`*[T](a: Matrix2x3[T], p: Point2D[T]): Point2D[T] = + let + x = a.M11*p.x + a.M12*p.y + a.M13 + y = a.M21*p.x + a.M22*p.y + a.M23 + + Point2D[T](x: x, y: y) + +# making these so things like "line" that need a constructor don't stick out. +# 2x2 determinant: |a b| +# |c d| = ad - bc + +# String rendering +# +template ff[S](x: S): string = + formatFloat(float(x), ffDefault, 0) + +proc `$`*[S](p: Point2D[S]): string = + "P($1, $2)" % [ff(p.x), ff(p.y)] + +proc `$`*[S](p: Vector2D[S]): string = + "V($1, $2)" % [ff(p.x), ff(p.y)] + +proc `$`*[S](m: Matrix2x3[S]): string = + "M($1 $2 $3/$4 $5 $6)" % [ff(m.M11), ff(m.M12), ff(m.M13), + ff(m.M21), ff(m.M22), ff(m.M23)] + +# +# Vector operators. +proc `-`*[S](a: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: -a.x, y: -a.y) + +proc `+`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x + b.x, y: a.y + b.y) + +proc `-`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x - b.x, y: a.y - b.y) + +proc `*`*[S](v: Vector2D[S], sc: S): Vector2D[S] = + Vector2D[S](x: v.x*sc, y: v.y*sc) + +proc `*`*[S](sc: S, v: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: v.x*sc, y: v.y*sc) + +proc `/`*[S](v: Vector2D[S], sc: S): Vector2D[S] = + Vector2D[S](x: v.x/sc, y: v.y/sc) + +proc `/`*[S](sc: S; v: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: sc/v.x, y: sc/v.y) + +proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x/b.x, y: a.y/b.y) +#proc vec[S](x, y: S): Vector2D[S] +proc vec[S](x, y: S): Vector2D[S] = + Vector2D[S](x: x, y: y) + +if isMainModule: + # Comment out this let, and the program will fail to + # compile with a type mismatch, as expected. + + let s3 = scale(vec(4.0, 4.0)) + let barf = translation(Point2D[float32](x: 1, y: 1)) * rotation(float(0.7)) + + echo "Badness ", barf diff --git a/tests/global/tglobal.nim b/tests/global/tglobal.nim index 84c4510c1..d44a62afc 100644 --- a/tests/global/tglobal.nim +++ b/tests/global/tglobal.nim @@ -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 diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index a507a08e4..060610ae0 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -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] = @[], diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim index a9759687f..3c5a7835c 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim @@ -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) diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim index 6dd1a6a7f..c2e893273 100644 --- a/tests/manyloc/keineschweine/enet_server/enet_server.nim +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -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""" diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index 0a5dc1efc..525d8a054 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -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 diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim index 966b84b6a..5776c9225 100644 --- a/tests/manyloc/keineschweine/lib/map_filter.nim +++ b/tests/manyloc/keineschweine/lib/map_filter.nim @@ -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) diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim index 9a6542d75..fcd0e8d24 100644 --- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim +++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim @@ -24,17 +24,17 @@ when isMainModule: import strutils var r = compress("Hello") echo repr(r) - var l = "Hello".len - var rr = uncompress(r, l) + var ln = "Hello".len + var rr = uncompress(r, ln) echo repr(rr) assert rr == "Hello" - proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a) + proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b) var s = "yo dude sup bruh homie" * 50 r = compress(s) echo s.len, " -> ", r.len - l = s.len - rr = uncompress(r, l) + ln = s.len + rr = uncompress(r, ln) echo r.len, " -> ", rr.len assert rr == s \ No newline at end of file diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim index ac85cbf62..1e57c12a1 100644 --- a/tests/manyloc/keineschweine/server/old_sg_server.nim +++ b/tests/manyloc/keineschweine/server/old_sg_server.nim @@ -174,7 +174,7 @@ when isMainModule: 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 diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim new file mode 100644 index 000000000..68a61373f --- /dev/null +++ b/tests/misc/parsecomb.nim @@ -0,0 +1,105 @@ +type Input[T] = object + toks: seq[T] + index: int + +type + ResultKind* = enum rkSuccess, rkFailure + Result*[T, O] = object + case kind*: ResultKind + of rkSuccess: + output*: O + input: Input[T] + of rkFailure: + nil + +type + Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O] + +proc unit*[T, O](v: O): Parser[T, O] = + Parser(proc (inp: Input[T]): Result[T, O] = + Result[T, O](kind: rkSuccess, output: v, input: inp)) + +proc fail*[T, O](): Parser[T, O] = + Parser(proc (inp: Input[T]): Result[T, O] = + Result(kind: rkFailure)) + +method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] = + # hmmm .. + type tmp = proc (input: Input[T]): Result[T, O] + # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C. + tmp(self)(inp) + +method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = + self.runInput(Input[T](toks: toks, index: 0)) + +method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = + Parser(proc (inp: Input[T]): Result[T, O2] = + let r = self.runInput(inp) + case r.kind: + of rkSuccess: + nextp(r.output).runInput(r.input) + of rkFailure: + Result[T, O2](kind: rkFailure)) + +method skip[T](self: Input[T], n: int): Input[T] = + Input[T](toks: self.toks, index: self.index + n) + +proc pskip*[T](n: int): Parser[T, tuple[]] = + Parser(proc (inp: Input[T]): Result[T, tuple[]] = + if inp.index + n <= inp.toks.len: + Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n)) + else: + Result[T, tuple[]](kind: rkFailure)) + +proc tok*[T](t: T): Parser[T, T] = + Parser(proc (inp: Input[T]): Result[T, T] = + if inp.index < inp.toks.len and inp.toks[inp.index] == t: + pskip[T](1).then(unit[T, T](t)).runInput(inp) + else: + Result[T, T](kind: rkFailure)) + +proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] = + Parser(proc (inp: Input[T]): Result[T, O] = + let r = first.runInput(inp) + case r.kind + of rkSuccess: + r + else: + second.runInput(inp)) + +# end of primitives (definitions involving Parser(..)) + +method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = + self.chain(proc (v: O1): Parser[T, O2] = + unit[T, O2](p(v))) + +method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = + self.chain(proc (v: O1): Parser[T, O2] = + next) + +proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] = + first.chain(proc (v1: O1): Parser[T, (O1, O2)] = + second.map(proc (v2: O2): (O1, O2) = + (v1, v2))) + +proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] = + var nothing = unit[T, seq[O]](@[]) + inner.chain(proc(v: O): Parser[T, seq[O]] = + repeat0(inner).map(proc(vs: seq[O]): seq[O] = + @[v] & vs)) + nothing + +proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] = + inner.chain(proc(v: O): Parser[T, seq[O]] = + repeat0(inner).map(proc(vs: seq[O]): seq[O] = + @[v] & vs)) + +proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] = + (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O = + var (i, asx) = ias + for a in asx: + i = fold(i, a) + i) + +proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] = + unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] = + inner()) diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim new file mode 100644 index 000000000..6fe539813 --- /dev/null +++ b/tests/misc/tparsecombnum.nim @@ -0,0 +1,55 @@ +import parsecomb + +discard """ + output: "-289096" +""" + +type Num = int + +# forward stuff +var exp3: Parser[string, Num] +var exp = lazy(proc(): Parser[string, Num] = exp3) + +var digit = (proc(): Parser[string, Num] = + result = tok("0").then(unit[string, Num](Num(0))) + for n in 1..9: + result = result + tok($n).then(unit[string, Num](Num(n))) +)() + +var num = repeat1(digit).map(proc(ds: seq[Num]): Num = + result = 0 + for d in ds: + result = result*10 + d) + +type Op = proc(a, b: Num): Num + +var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b)) +var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b)) +var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b)) +var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b)) + +var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num = + var (le, r) = ler + var (l, e) = le + e) + +proc foldOp(a: Num, ob: (Op, Num)): Num = + var (o, b) = ob + o(a, b) + +var exp0 = paren + num +var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp) +var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp) +exp3 = exp2 + +proc strsplit(s: string): seq[string] = + result = @[] + for i in 0 .. s.len - 1: + result.add($s[i]) + +var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit) +case r.kind: +of rkSuccess: + echo r.output +of rkFailure: + echo "failed" diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim index f9fbd5e40..dda8057b6 100644 --- a/tests/objects/tobjpragma.nim +++ b/tests/objects/tobjpragma.nim @@ -7,8 +7,11 @@ discard """ 1 2 3''' + disabled: "true" """ +# Disabled since some versions of GCC ignore the 'packed' attribute + # Test type diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim new file mode 100644 index 000000000..2700bed5e --- /dev/null +++ b/tests/overload/tprefer_tygenericinst.nim @@ -0,0 +1,17 @@ +discard """ + output: "Version 2 was called." + disabled: true +""" + +# bug #2220 + +type A[T] = object +type B = A[int] + +proc p[X](x: X) = + echo "Version 1 was called." + +proc p(x: B) = + echo "Version 2 was called." + +p(B()) # This call reported as ambiguous. diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim new file mode 100644 index 000000000..b5551bcc7 --- /dev/null +++ b/tests/overload/tsymtabchange_during_or.nim @@ -0,0 +1,24 @@ + +# bug #2229 + +type Type1 = object + id: int + +type Type2 = object + id: int + +proc init(self: var Type1, a: int, b: ref Type2) = + echo "1" + +proc init(self: var Type2, a: int) = + echo """ + Works when this proc commented out + Otherwise error: + test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2) + """ + +var a: Type1 +init(a, 1, ( + var b = new(Type2); + b +)) diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 1b83aab53..a778d2f77 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -6,11 +6,11 @@ import marshal template testit(x: expr) = discard $$to[type(x)]($$x) -var x: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] -testit(x) +var x: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] +testit(x) var test2: tuple[name: string, s: int] = ("tuple test", 56) testit(test2) @@ -24,7 +24,7 @@ type of blah: help: string else: - nil + discard PNode = ref TNode TNode = object diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index ce9094bc0..3db484faa 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -46,7 +46,13 @@ assert "/1/2/3".rfind('0') == -1 assert(toHex(100i16, 32) == "00000000000000000000000000000064") assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") -main() -#OUT ha/home/a1xyz/usr/bin +assert(' '.repeat(8)== " ") +assert(" ".repeat(8) == " ") +assert(spaces(8) == " ") +assert(' '.repeat(0) == "") +assert(" ".repeat(0) == "") +assert(spaces(0) == "") +main() +#OUT ha/home/a1xyz/usr/bin diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim new file mode 100644 index 000000000..32af9e8f7 --- /dev/null +++ b/tests/template/texponential_eval.nim @@ -0,0 +1,47 @@ +# bug #1940 + +discard """ + nimout: '''=== +merge (A) with (B) +merge (A B) with (C) +merge (A B C) with (D) +merge (A B C D) with (E) +merge (A B C D E) with (F) +===''' +""" + +type SqlStmt = tuple + sql: string + parts: int + +proc sql(q: string): SqlStmt = + result.sql = q + result.parts = 1 + +template `&%%`(x, y: SqlStmt): SqlStmt = + const a = x + const b = y + + static: + #echo "some merge" + echo "merge (", a.sql, ") with (", b.sql, ")" + + + const newSql = a.sql & " " & b.sql + const newParts = a.parts + b.parts + + SqlStmt((sql: newSql, parts: newParts)) + +static: + echo "===" + +let c =(sql("A") &%% + sql("B")) &%% + sql("C") &%% + sql("D") &%% + sql("E") &%% + sql("F") +echo c.sql + +static: + echo "===" diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index ed4d27cab..323abd768 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -230,17 +230,17 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = else: testNoSpec r, makeTest(test, options, cat, actionCompile) -# ----------------------------- babel ---------------------------------------- +# ----------------------------- nimble ---------------------------------------- type PackageFilter = enum pfCoreOnly pfExtraOnly pfAll let - babelExe = findExe("babel") - babelDir = getHomeDir() / ".babel" - packageDir = babelDir / "pkgs" - packageIndex = babelDir / "packages.json" + nimbleExe = findExe("nimble") + nimbleDir = getHomeDir() / ".nimble" + packageDir = nimbleDir / "pkgs" + packageIndex = nimbleDir / "packages.json" proc waitForExitEx(p: Process): int = var outp = outputStream(p) @@ -255,7 +255,7 @@ proc waitForExitEx(p: Process): int = proc getPackageDir(package: string): string = ## TODO - Replace this with dom's version comparison magic. - var commandOutput = execCmdEx("babel path $#" % package) + var commandOutput = execCmdEx("nimble path $#" % package) if commandOutput.exitCode != QuitSuccess: return "" else: @@ -268,7 +268,7 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] = let name = package["name"].str url = package["url"].str - isCorePackage = "nimrod-code" in normalize(url) + isCorePackage = "nim-lang" in normalize(url) case filter: of pfCoreOnly: if isCorePackage: @@ -279,13 +279,13 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] = of pfAll: yield (name, url) -proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = - if babelExe == "": - echo("[Warning] - Cannot run babel tests: Babel binary not found.") +proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) = + if nimbleExe == "": + echo("[Warning] - Cannot run nimble tests: Nimble binary not found.") return - if execCmd("$# update" % babelExe) == QuitFailure: - echo("[Warning] - Cannot run babel tests: Babel update failed.") + if execCmd("$# update" % nimbleExe) == QuitFailure: + echo("[Warning] - Cannot run nimble tests: Nimble update failed.") return let packageFileTest = makeTest("PackageFileParsed", "", cat) @@ -294,7 +294,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = var test = makeTest(name, "", cat) echo(url) let - installProcess = startProcess(babelExe, "", ["install", "-y", name]) + installProcess = startProcess(nimbleExe, "", ["install", "-y", name]) installStatus = waitForExitEx(installProcess) installProcess.close if installStatus != QuitSuccess: @@ -302,9 +302,8 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = continue let - buildPath = getPackageDir(name)[0.. -3] - let - buildProcess = startProcess(babelExe, buildPath, ["build"]) + buildPath = getPackageDir(name).strip + buildProcess = startProcess(nimbleExe, buildPath, ["build"]) buildStatus = waitForExitEx(buildProcess) buildProcess.close if buildStatus != QuitSuccess: @@ -312,13 +311,13 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = r.addResult(test, "", "", reSuccess) r.addResult(packageFileTest, "", "", reSuccess) except JsonParsingError: - echo("[Warning] - Cannot run babel tests: Invalid package file.") + echo("[Warning] - Cannot run nimble tests: Invalid package file.") r.addResult(packageFileTest, "", "", reBuildFailed) # ---------------------------------------------------------------------------- -const AdditionalCategories = ["debugger", "examples", "lib", "babel-core"] +const AdditionalCategories = ["debugger", "examples", "lib"] proc `&.?`(a, b: string): string = # candidate for the stdlib? @@ -356,12 +355,12 @@ proc processCategory(r: var TResults, cat: Category, options: string) = compileExample(r, "examples/*.nim", options, cat) compileExample(r, "examples/gtk/*.nim", options, cat) compileExample(r, "examples/talk/*.nim", options, cat) - of "babel-core": - testBabelPackages(r, cat, pfCoreOnly) - of "babel-extra": - testBabelPackages(r, cat, pfExtraOnly) - of "babel-all": - testBabelPackages(r, cat, pfAll) + of "nimble-core": + testNimblePackages(r, cat, pfCoreOnly) + of "nimble-extra": + testNimblePackages(r, cat, pfExtraOnly) + of "nimble-all": + testNimblePackages(r, cat, pfAll) else: for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"): testSpec r, makeTest(name, options, cat) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 881a41ce6..0a0d08173 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -141,7 +141,7 @@ proc generatedFile(path, name: string, target: TTarget): string = (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") & name.changeFileExt(ext) -proc codegenCheck(test: TTest, check: string, given: var TSpec) = +proc codegenCheck(test: TTest, check: string, given: var TSpec, r: var TResults) = if check.len > 0: try: let (path, name, ext2) = test.name.splitFile @@ -154,19 +154,29 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) = given.err = reInvalidPeg except IOError: given.err = reCodeNotFound + r.addResult(test, "", given.msg, given.err) -proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = +proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec, r: var TResults) = if expectedNimout.len > 0: let exp = expectedNimout.strip.replace("\C\L", "\L") let giv = given.nimout.strip.replace("\C\L", "\L") if exp notin giv: given.err = reMsgsDiffer + r.addResult(test, exp, giv, given.err) + proc makeDeterministic(s: string): string = var x = splitLines(s) sort(x, system.cmp) result = join(x, "\n") +proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec, r: var TResults) = + if given.err == reSuccess: + codegenCheck(test, expected.ccodeCheck, given, r) + nimoutCheck(test, expected.nimout, given, r) + if given.err == reSuccess: inc(r.passed) + + proc testSpec(r: var TResults, test: TTest) = # major entry point for a single test let tname = test.name.addFileExt(".nim") @@ -179,13 +189,9 @@ proc testSpec(r: var TResults, test: TTest) = else: case expected.action of actionCompile: - var given = callCompiler(expected.cmd, test.name, test.options, - test.target) - if given.err == reSuccess: - codegenCheck(test, expected.ccodeCheck, given) - nimoutCheck(test, expected.nimout, given) - r.addResult(test, "", given.msg, given.err) - if given.err == reSuccess: inc(r.passed) + var given = callCompiler(expected.cmd, test.name, + test.options & " --hint[Path]:off --hint[Processing]:off", test.target) + compilerOutputTests(test, given, expected, r) of actionRun: var given = callCompiler(expected.cmd, test.name, test.options, test.target) @@ -215,11 +221,7 @@ proc testSpec(r: var TResults, test: TTest) = if bufB != strip(expected.outp): if not (expected.substr and expected.outp in bufB): given.err = reOutputsDiffer - if given.err == reSuccess: - codeGenCheck(test, expected.ccodeCheck, given) - nimoutCheck(test, expected.nimout, given) - if given.err == reSuccess: inc(r.passed) - r.addResult(test, expected.outp, buf.string, given.err) + compilerOutputTests(test, given, expected, r) else: r.addResult(test, expected.outp, "executable not found", reExeNotFound) of actionReject: diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim index dc72a96cd..500851582 100644 --- a/tests/trmacros/tor.nim +++ b/tests/trmacros/tor.nim @@ -1,5 +1,5 @@ discard """ - output: '''3060 + output: '''3030 true 3''' """ diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim index 96a1bafe8..4459931c5 100644 --- a/tests/vm/tconsteval.nim +++ b/tests/vm/tconsteval.nim @@ -24,7 +24,7 @@ Possible Commands: csource [options] builds the C sources for installation zip builds the installation ZIP package inno builds the Inno Setup installer -""" % [NimVersion & repeatChar(44-len(NimVersion)), +""" % [NimVersion & spaces(44-len(NimVersion)), CompileDate, CompileTime] echo HelpText diff --git a/todo.txt b/todo.txt index 3fed10aeb..1d180f737 100644 --- a/todo.txt +++ b/todo.txt @@ -5,6 +5,8 @@ version 0.10.4 - make 'nil' work for 'add' and 'len' - get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}' - 'result' shadowing warning +- disallow negative indexing +- improve the parser; deal with echo $foo gotcha version 1.0 @@ -75,8 +77,7 @@ version 0.9.X ============= - macros as type pragmas -- lazy overloading resolution: - * special case ``tyStmt`` +- document how lazy overloading resolution works - document NimMain and check whether it works for threading GC diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index aeae86300..72e4adc07 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -109,7 +109,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int], for i in t.last+1 .. y: stdout.write(s[i]) stdout.write("\n") if showRepl: - stdout.write(repeatChar(alignment-1), "-> ") + stdout.write(spaces(alignment-1), "-> ") for i in x .. t.first-1: stdout.write(s[i]) writeColored(repl) for i in t.last+1 .. y: stdout.write(s[i]) diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 8213cf418..a7301195e 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -99,8 +99,8 @@ macro updated(e: expr): expr {.immediate.} = proc updatedDate(year, month, day: string): string = ## wrapper around the update macro with easy input. result = updated("$1-$2-$3T00:00:00Z" % [year, - repeatStr(2 - len(month), "0") & month, - repeatStr(2 - len(day), "0") & day]) + repeat("0", 2 - len(month)) & month, + repeat("0", 2 - len(day)) & day]) macro entry(e: expr): expr {.immediate.} = ## generates the rss xml ``entry`` element. diff --git a/web/website.ini b/web/website.ini index 696829764..6266f05bb 100644 --- a/web/website.ini +++ b/web/website.ini @@ -59,6 +59,7 @@ srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite" srcdoc2: "packages/docutils/rst;packages/docutils/rstast" srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet" srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future" +srcdoc2: "pure/asyncfile" srcdoc2: "pure/md5" srcdoc2: "posix/posix" srcdoc2: "pure/fenv" |