diff options
Diffstat (limited to 'rod/ast.nim')
-rw-r--r-- | rod/ast.nim | 1090 |
1 files changed, 0 insertions, 1090 deletions
diff --git a/rod/ast.nim b/rod/ast.nim deleted file mode 100644 index fde238eaa..000000000 --- a/rod/ast.nim +++ /dev/null @@ -1,1090 +0,0 @@ -# -# -# The Nimrod Compiler -# (c) Copyright 2009 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# abstract syntax tree + symbol table - -import - msgs, nhashes, nversion, options, strutils, crc, ropes, idents, lists - -const - ImportTablePos* = 0 - ModuleTablePos* = 1 - -type - TCallingConvention* = enum - ccDefault, # proc has no explicit calling convention - ccStdCall, # procedure is stdcall - ccCDecl, # cdecl - ccSafeCall, # safecall - ccSysCall, # system call - ccInline, # proc should be inlined - ccNoInline, # proc should not be inlined - ccFastCall, # fastcall (pass parameters in registers) - ccClosure, # proc has a closure - ccNoConvention # needed for generating proper C procs sometimes - -const - CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", - "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure", - "noconv"] - -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 - # Expressions: - # Atoms: - nkEmpty, # the node is empty - nkIdent, # node is an identifier - nkSym, # node is a symbol - nkType, # node is used for its typ field - - nkCharLit, # a character literal '' - nkIntLit, # an integer literal - nkInt8Lit, - nkInt16Lit, - nkInt32Lit, - nkInt64Lit, - nkFloatLit, # a floating point literal - nkFloat32Lit, - nkFloat64Lit, - nkStrLit, # a string literal "" - nkRStrLit, # a raw string literal r"" - nkTripleStrLit, # a triple string literal """ - nkMetaNode, # difficult to explan; represents itself - # (used for macros) - nkNilLit, # the nil literal - # end of atoms - 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 - # x"abc" has two sons: nkIdent, nkRStrLit - # x"""abc""" has two sons: nkIdent, nkTripleStrLit - nkExprEqExpr, # a named parameter with equals: ''expr = expr'' - nkExprColonExpr, # a named parameter with colon: ''expr: expr'' - nkIdentDefs, # a definition like `a, b: typeDesc = expr` - # either typeDesc or expr may be nil; used in - # formal parameters, var statements, etc. - nkVarTuple, # a ``var (a, b) = expr`` construct - nkInfix, # a call like (a + b) - nkPrefix, # a call like !a - nkPostfix, # something like a! (also used for visibility) - nkPar, # syntactic (); may be a tuple constructor - nkCurly, # syntactic {} - nkBracket, # syntactic [] - nkBracketExpr, # an expression like a[i..j, k] - nkPragmaExpr, # an expression like a{.pragmas.} - nkRange, # an expression like i..j - nkDotExpr, # a.b - nkCheckedFieldExpr, # a.b, but b is a field that needs to be checked - nkDerefExpr, # a^ - nkIfExpr, # if as an expression - nkElifExpr, - nkElseExpr, - nkLambda, # lambda expression - nkAccQuoted, # `a` as a node - - nkTableConstr, # a table constructor {expr: expr} - nkBind, # ``bind expr`` node - nkSymChoice, # symbol choice node - nkHiddenStdConv, # an implicit standard type conversion - nkHiddenSubConv, # an implicit type conversion from a subtype - # to a supertype - nkHiddenCallConv, # an implicit type conversion via a type converter - nkConv, # a type conversion - nkCast, # a type cast - nkAddr, # a addr expression - nkHiddenAddr, # implicit address operator - nkHiddenDeref, # implicit ^ operator - nkObjDownConv, # down conversion between object types - nkObjUpConv, # up conversion between object types - nkChckRangeF, # range check for floats - nkChckRange64, # range check for 64 bit ints - nkChckRange, # range check for ints - nkStringToCString, # string to cstring - nkCStringToString, # cstring to string - nkPassAsOpenArray, # thing is passed as an open array - # end of expressions - - nkAsgn, # a = b - nkFastAsgn, # internal node for a fast ``a = b`` (no string copy) - nkGenericParams, # generic parameters - nkFormalParams, # formal parameters - nkOfInherit, # inherited from symbol - - nkModule, # the syntax tree of a module - nkProcDef, # a proc - nkMethodDef, # a method - nkConverterDef, # a converter - nkMacroDef, # a macro - nkTemplateDef, # a template - nkIteratorDef, # an iterator - - nkOfBranch, # used inside case statements for (cond, action)-pairs - nkElifBranch, # used in if statements - nkExceptBranch, # an except section - nkElse, # an else part - nkMacroStmt, # a macro statement - nkAsmStmt, # an assembler block - nkPragma, # a pragma statement - nkIfStmt, # an if statement - nkWhenStmt, # a when statement - nkForStmt, # a for statement - nkWhileStmt, # a while statement - nkCaseStmt, # a case statement - nkVarSection, # a var section - nkConstSection, # a const section - nkConstDef, # a const definition - nkTypeSection, # a type section (consists of type definitions) - nkTypeDef, # a type definition - nkYieldStmt, # the yield statement as a tree - nkTryStmt, # a try statement - nkFinally, # a finally section - nkRaiseStmt, # a raise statement - nkReturnStmt, # a return statement - nkBreakStmt, # a break statement - nkContinueStmt, # a continue statement - nkBlockStmt, # a block statement - nkDiscardStmt, # a discard statement - nkStmtList, # a list of statements - nkImportStmt, # an import statement - nkFromStmt, # a from * import statement - nkIncludeStmt, # an include statement - nkCommentStmt, # a comment statement - nkStmtListExpr, # a statement list followed by an expr; this is used - # to allow powerful multi-line templates - nkBlockExpr, # a statement block ending in an expr; this is used - # to allowe powerful multi-line templates that open a - # temporary scope - nkStmtListType, # a statement list ending in a type; for macros - nkBlockType, # a statement block ending in a type; for macros - # types as syntactic trees: - nkTypeOfExpr, - nkObjectTy, - nkTupleTy, - nkRecList, # list of object parts - nkRecCase, # case section of object - nkRecWhen, # when section of object - nkRefTy, - nkPtrTy, - nkVarTy, - nkDistinctTy, # distinct type - nkProcTy, - nkEnumTy, - nkEnumFieldDef, # `ident = expr` in an enumeration - nkReturnToken # token used for interpretation - TNodeKinds* = set[TNodeKind] - -type - TSymFlag* = enum # already 30 flags! - sfUsed, # read access of sym (for warnings) or simply used - sfStar, # symbol has * visibility - sfMinus, # symbol has - visibility - sfInInterface, # symbol is in interface section declared - 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 - - sfForward, # symbol is forward directed - sfImportc, # symbol is external; imported - sfExportc, # symbol is exported (under a specified name) - sfVolatile, # variable is volatile - sfRegister, # variable should be placed in a register - sfPure, # object is "pure" that means it has no type-information - - sfResult, # variable is 'result' in proc - sfNoSideEffect, # proc has no side effects - sfSideEffect, # proc may have side effects; cannot prove it has none - sfMainModule, # module is the main module - sfSystemModule, # module is the system module - sfNoReturn, # proc never returns (an exit proc) - sfAddrTaken, # the variable's address is taken (ex- or implicitely) - sfCompilerProc, # proc is a compiler proc, that is a C proc that is - # needed for the code generator - sfProcvar, # proc can be passed to a proc var - sfDiscriminant, # field is a discriminant in a record/object - sfDeprecated, # symbol is deprecated - sfInClosure, # variable is accessed by a closure - sfTypeCheck, # wether macro parameters should be type checked - sfCompileTime, # proc can be evaluated at compile time - sfThreadVar, # variable is a thread variable - sfMerge, # proc can be merged with itself - sfDeadCodeElim, # dead code elimination for the module is turned on - sfBorrow # proc is borrowed - - TSymFlags* = set[TSymFlag] - - TTypeKind* = enum # order is important! - # Don't forget to change hti.nim if you make a change here - # XXX put this into an include file to avoid this issue! - tyNone, tyBool, tyChar, - tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc, - tyGenericInvokation, # ``T[a, b]`` for types to invoke - tyGenericBody, # ``T[a, b, body]`` last parameter is the body - tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type - tyGenericParam, # ``a`` in the example - tyDistinct, - tyEnum, - tyOrdinal, - tyArray, - tyObject, - tyTuple, - tySet, - tyRange, - tyPtr, tyRef, - tyVar, - tySequence, - tyProc, - tyPointer, tyOpenArray, - tyString, tyCString, tyForward, - tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers - tyFloat, tyFloat32, tyFloat64, tyFloat128 - - TTypeKinds* = set[TTypeKind] - - TNodeFlag* = enum - nfNone, - nfBase2, # nfBase10 is default, so not needed - nfBase8, - nfBase16, - nfAllConst, # used to mark complex expressions constant - nfTransf, # node has been transformed - nfSem # node has been checked for semantics - - TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum - tfVarargs, # procedure has C styled varargs - tfNoSideEffect, # procedure type does not allow side effects - tfFinal, # is the object final? - tfAcyclic, # type is acyclic (for GC optimization) - tfEnumHasWholes # enum cannot be mapped into a range - - TTypeFlags* = set[TTypeFlag] - - TSymKind* = enum # the different symbols (start with the prefix sk); - # order is important for the documentation generator! - skUnknown, # unknown symbol: used for parsing assembler blocks - # and first phase symbol lookup in generics - skConditional, # symbol for the preprocessor (may become obsolete) - skDynLib, # symbol represents a dynamic library; this is used - # internally; it does not exist in Nimrod code - skParam, # a parameter - skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()`` - skTemp, # a temporary variable (introduced by compiler) - skType, # a type - skConst, # a constant - skVar, # a variable - skProc, # a proc - skMethod, # a method - skIterator, # an iterator - skConverter, # a type converter - skMacro, # a macro - skTemplate, # a template - skField, # a field in a record or object - skEnumField, # an identifier in an enum - skForVar, # a for loop variable - skModule, # module identifier - skLabel, # a label (for block statement) - skStub # symbol is a stub and not yet loaded from the ROD - # file (it is loaded on demand, which may mean: never) - TSymKinds* = set[TSymKind] - - TMagic* = enum # symbols that require compiler magic: - mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mEcho, 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, - mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64, - mMinF64, mMaxF64, mAddU, mSubU, mMulU, - mDivU, mModU, mAddU64, mSubU64, mMulU64, mDivU64, mModU64, 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, - mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, - mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mArray, - mOpenArray, mRange, mSet, mSeq, mOrdinal, mInt, mInt8, mInt16, mInt32, - mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mString, mCstring, - mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, - mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, - mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mNaN, mInf, - mNegInf, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, - mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, - mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, - mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, - mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError - -type - PNode* = ref TNode - PNodePtr* = ptr PNode - TNodeSeq* = seq[PNode] - PType* = ref TType - PSym* = ref TSym - TNode*{.acyclic, final.} = object # on a 32bit machine, this takes 32 bytes - typ*: PType - comment*: string - info*: TLineInfo - flags*: TNodeFlags - case Kind*: TNodeKind - of nkCharLit..nkInt64Lit: - intVal*: biggestInt - of nkFloatLit..nkFloat64Lit: - floatVal*: biggestFloat - of nkStrLit..nkTripleStrLit: - strVal*: string - of nkSym: - sym*: PSym - of nkIdent: - ident*: PIdent - else: - sons*: TNodeSeq - - TSymSeq* = seq[PSym] - TStrTable* = object # a table[PIdent] of PSym - counter*: int - data*: TSymSeq - - # -------------- backend information ------------------------------- - TLocKind* = enum - locNone, # no location - locTemp, # temporary location - locLocalVar, # location is a local variable - locGlobalVar, # location is a global variable - locParam, # location is a parameter - locField, # location is a record field - locArrayElem, # location is an array element - locExpr, # "location" is really an expression - locProc, # location is a proc (an address of a procedure) - locData, # location is a constant - locCall, # location is a call expression - locOther # location is something other - TLocFlag* = enum - lfIndirect, # backend introduced a pointer - lfParamCopy, # backend introduced a parameter copy (LLVM) - lfNoDeepCopy, # no need for a deep copy - lfNoDecl, # do not declare it in C - lfDynamicLib, # link symbol to dynamic library - lfExportLib, # export symbol for dynamic library generation - lfHeader # include header file for symbol - 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*{.final.} = object - k*: TLocKind # kind of location - s*: TStorageLoc - flags*: TLocFlags # location's flags - t*: PType # type of location - r*: PRope # rope value of location (code generators) - a*: int # location's "address", i.e. slot for temporaries - - # ---------------- end of backend information ------------------------------ - - TLibKind* = enum - libHeader, libDynamic - TLib* = object of lists.TListEntry # also misused for headers! - kind*: TLibKind - generated*: bool # needed for the backends: - name*: PRope - path*: PNode # can be a string literal! - - - PLib* = ref TLib - TSym* = object of TIdObj - kind*: TSymKind - magic*: TMagic - typ*: PType - name*: PIdent - info*: TLineInfo - owner*: PSym - flags*: TSymFlags - tab*: TStrTable # interface table for modules - ast*: PNode # syntax tree of proc, iterator, etc.: - # the whole proc including header; this is used - # for easy generation of proper error messages - # for variant record fields the discriminant - # expression - options*: TOptions - position*: int # used for many different things: - # for enum fields its position; - # for fields its offset - # for parameters its position - # for a conditional: - # 1 iff the symbol is defined, else 0 - # (or not in symbol table) - offset*: int # offset of record field - loc*: TLoc - annex*: PLib # additional fields (seldom used, so we use a - # reference to another object to safe space) - - TTypeSeq* = seq[PType] - TType* = object of TIdObj # types are identical iff they have the - # same id; there may be multiple copies of a type - # in memory! - kind*: TTypeKind # kind of type - sons*: TTypeSeq # base types, etc. - n*: PNode # node for types: - # for range types a nkRange node - # for record types a nkRecord node - # for enum types a list of symbols - # else: unused - flags*: TTypeFlags # flags of the type - callConv*: TCallingConvention # for procs - owner*: PSym # the 'owner' of the type - sym*: PSym # types have the sym associated with them - # it is used for converting types to strings - size*: BiggestInt # the size of the type in bytes - # -1 means that the size is unkwown - align*: int # the type's alignment requirements - containerID*: int # used for type checking of generics - loc*: TLoc - - TPair*{.final.} = object - key*, val*: PObject - - TPairSeq* = seq[TPair] - TTable*{.final.} = object # the same as table[PObject] of PObject - counter*: int - data*: TPairSeq - - TIdPair*{.final.} = object - key*: PIdObj - val*: PObject - - TIdPairSeq* = seq[TIdPair] - TIdTable*{.final.} = object # the same as table[PIdent] of PObject - counter*: int - data*: TIdPairSeq - - TIdNodePair*{.final.} = object - key*: PIdObj - val*: PNode - - TIdNodePairSeq* = seq[TIdNodePair] - TIdNodeTable*{.final.} = object # the same as table[PIdObj] of PNode - counter*: int - data*: TIdNodePairSeq - - TNodePair*{.final.} = object - h*: THash # because it is expensive to compute! - key*: PNode - val*: int - - TNodePairSeq* = seq[TNodePair] - TNodeTable*{.final.} = object # the same as table[PNode] of int; - # nodes are compared by structure! - counter*: int - data*: TNodePairSeq - - TObjectSeq* = seq[PObject] - TObjectSet*{.final.} = object - counter*: int - data*: TObjectSeq - -# BUGFIX: a module is overloadable so that a proc can have the -# same name as an imported module. This is necessary because of -# the poor naming choices in the standard library. - -const - OverloadableSyms* = {skProc, skMethod, skIterator, skConverter, skModule} - - GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, - tyGenericParam} - StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, - tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray} - ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: - # var x = expr - tyBool, tyChar, tyEnum, tyArray, tyObject, - tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128} - - ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple} - ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, - skMacro, skTemplate, skConverter, skStub} - PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst} - namePos* = 0 - genericParamsPos* = 1 - paramsPos* = 2 - pragmasPos* = 3 - codePos* = 4 - resultPos* = 5 - dispatcherPos* = 6 - -var gId*: int - -proc getID*(): int -proc setID*(id: int) -proc IDsynchronizationPoint*(idRange: int) - -# creator procs: -proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym -proc NewType*(kind: TTypeKind, owner: PSym): PType -proc newNode*(kind: TNodeKind): PNode -proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode -proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode -proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode -proc newStrNode*(kind: TNodeKind, strVal: string): PNode -proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode -proc newSymNode*(sym: PSym): PNode -proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode -proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode -proc initStrTable*(x: var TStrTable) -proc initTable*(x: var TTable) -proc initIdTable*(x: var TIdTable) -proc initObjectSet*(x: var TObjectSet) -proc initIdNodeTable*(x: var TIdNodeTable) -proc initNodeTable*(x: var TNodeTable) - -# copy procs: -proc copyType*(t: PType, owner: PSym, keepId: bool): PType -proc copySym*(s: PSym, keepId: bool = false): PSym -proc assignType*(dest, src: PType) -proc copyStrTable*(dest: var TStrTable, src: TStrTable) -proc copyTable*(dest: var TTable, src: TTable) -proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) -proc copyIdTable*(dest: var TIdTable, src: TIdTable) -proc sonsLen*(n: PNode): int -proc sonsLen*(n: PType): int -proc lastSon*(n: PNode): PNode -proc lastSon*(n: PType): PType -proc newSons*(father: PNode, length: int) -proc newSons*(father: PType, length: int) -proc addSon*(father, son: PNode) -proc addSon*(father, son: PType) -proc addSonIfNotNil*(father, n: PNode) -proc delSon*(father: PNode, idx: int) -proc hasSonWith*(n: PNode, kind: TNodeKind): bool -proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool -proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind) -proc sonsNotNil*(n: PNode): bool -proc copyNode*(src: PNode): PNode - # does not copy its sons! -proc copyTree*(src: PNode): PNode - # does copy its sons! - -proc discardSons*(father: PNode) - -const # for all kind of hash tables: - GrowthFactor* = 2 # must be power of 2, > 0 - StartSize* = 8 # must be power of 2, > 0 - -proc SameValue*(a, b: PNode): bool - # a, b are literals -proc leValue*(a, b: PNode): bool - # a <= b? a, b are literals -proc ValueToString*(a: PNode): string - -# ------------- efficient integer sets ------------------------------------- -type - TBitScalar* = int - -const - InitIntSetSize* = 8 # must be a power of two! - TrunkShift* = 9 - BitsPerTrunk* = 1 shl TrunkShift # needs to be a power of 2 and divisible by 64 - TrunkMask* = BitsPerTrunk - 1 - IntsPerTrunk* = BitsPerTrunk div (sizeof(TBitScalar) * 8) - IntShift* = 5 + ord(sizeof(TBitScalar) == 8) # 5 or 6, depending on int width - IntMask* = 1 shl IntShift - 1 - -type - PTrunk* = ref TTrunk - TTrunk*{.final.} = object - next*: PTrunk # all nodes are connected with this pointer - key*: int # start address at bit 0 - bits*: array[0..IntsPerTrunk - 1, TBitScalar] # a bit vector - - TTrunkSeq* = seq[PTrunk] - TIntSet*{.final.} = object - counter*, max*: int - head*: PTrunk - data*: TTrunkSeq - - -proc IntSetContains*(s: TIntSet, key: int): bool -proc IntSetIncl*(s: var TIntSet, key: int) -proc IntSetExcl*(s: var TIntSet, key: int) -proc IntSetInit*(s: var TIntSet) -proc IntSetContainsOrIncl*(s: var TIntSet, key: int): bool -const - debugIds* = false - -proc registerID*(id: PIdObj) -# implementation - -var usedIds: TIntSet - -proc registerID(id: PIdObj) = - if debugIDs: - if (id.id == - 1) or IntSetContainsOrIncl(usedIds, id.id): - InternalError("ID already used: " & $(id.id)) - -proc getID(): int = - result = gId - inc(gId) - -proc setId(id: int) = - gId = max(gId, id + 1) - -proc IDsynchronizationPoint(idRange: int) = - gId = (gId div IdRange + 1) * IdRange + 1 - -proc leValue(a, b: PNode): bool = - # a <= b? - result = false - case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal - of nkFloatLit..nkFloat64Lit: - if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal - of nkStrLit..nkTripleStrLit: - if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal - else: InternalError(a.info, "leValue") - -proc SameValue(a, b: PNode): bool = - result = false - case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: - if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal - of nkStrLit..nkTripleStrLit: - if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal - else: InternalError(a.info, "SameValue") - -proc ValueToString(a: PNode): string = - case a.kind - of nkCharLit..nkInt64Lit: result = $(a.intVal) - of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result = $(a.floatVal) - of nkStrLit..nkTripleStrLit: result = a.strVal - else: - InternalError(a.info, "valueToString") - result = "" - -proc copyStrTable(dest: var TStrTable, src: TStrTable) = - dest.counter = src.counter - 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) = - dest.counter = src.counter - 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) = - dest.counter = src.counter - 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) = - dest.counter = src.counter - 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) = - father.sons = nil - -proc newNode(kind: TNodeKind): PNode = - new(result) - result.kind = kind #result.info := UnknownLineInfo(); inlined: - result.info.fileIndex = int32(- 1) - result.info.col = int16(- 1) - result.info.line = int16(- 1) - -proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode = - result = newNode(kind) - result.intVal = intVal - -proc newIntTypeNode(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = - result = newIntNode(kind, intVal) - result.typ = typ - -proc newFloatNode(kind: TNodeKind, floatVal: BiggestFloat): PNode = - result = newNode(kind) - result.floatVal = floatVal - -proc newStrNode(kind: TNodeKind, strVal: string): PNode = - result = newNode(kind) - result.strVal = strVal - -proc newIdentNode(ident: PIdent, info: TLineInfo): PNode = - result = newNode(nkIdent) - result.ident = ident - result.info = info - -proc newSymNode(sym: PSym): PNode = - result = newNode(nkSym) - result.sym = sym - result.typ = sym.typ - result.info = sym.info - -proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode = - result = newNode(kind) - result.info = info - -proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = - result = newNode(kind) - result.info = info - result.typ = typ - -proc NewType(kind: TTypeKind, owner: PSym): PType = - new(result) - result.kind = kind - result.owner = owner - result.size = - 1 - result.align = 2 # default alignment - result.id = getID() - if debugIds: - RegisterId(result) #if result.id < 2000 then - # MessageOut(typeKindToStr[kind] +{&} ' has id: ' +{&} toString(result.id)); - -proc assignType(dest, src: PType) = - dest.kind = src.kind - dest.flags = src.flags - dest.callConv = src.callConv - dest.n = src.n - dest.size = src.size - dest.align = src.align - dest.containerID = src.containerID - 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 = - result = newType(t.Kind, owner) - assignType(result, t) - if keepId: - result.id = t.id - else: - result.id = getID() - if debugIds: RegisterId(result) - result.sym = t.sym # backend-info should not be copied - -proc copySym(s: PSym, keepId: bool = false): PSym = - result = newSym(s.kind, s.name, s.owner) - result.ast = nil # BUGFIX; was: s.ast which made problems - result.info = s.info - result.typ = s.typ - if keepId: - result.id = s.id - else: - result.id = getID() - if debugIds: RegisterId(result) - result.flags = s.flags - result.magic = s.magic - copyStrTable(result.tab, s.tab) - result.options = s.options - result.position = s.position - result.loc = s.loc - result.annex = s.annex # BUGFIX - -proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym): PSym = - # generates a symbol and initializes the hash field too - new(result) - result.Name = Name - result.Kind = symKind - result.flags = {} - result.info = UnknownLineInfo() - result.options = gOptions - result.owner = owner - result.offset = - 1 - result.id = getID() - if debugIds: - RegisterId(result) #if result.id < 2000 then - # MessageOut(name.s +{&} ' has id: ' +{&} toString(result.id)); - -proc initStrTable(x: var TStrTable) = - x.counter = 0 - newSeq(x.data, startSize) - -proc initTable(x: var TTable) = - x.counter = 0 - newSeq(x.data, startSize) - -proc initIdTable(x: var TIdTable) = - x.counter = 0 - newSeq(x.data, startSize) - -proc initObjectSet(x: var TObjectSet) = - x.counter = 0 - newSeq(x.data, startSize) - -proc initIdNodeTable(x: var TIdNodeTable) = - x.counter = 0 - newSeq(x.data, startSize) - -proc initNodeTable(x: var TNodeTable) = - x.counter = 0 - newSeq(x.data, startSize) - -proc sonsLen(n: PType): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc newSons(father: PType, length: int) = - if isNil(father.sons): father.sons = @[] - setlen(father.sons, len(father.sons) + length) - -proc addSon(father, son: PType) = - if isNil(father.sons): father.sons = @[] - add(father.sons, son) - assert((father.kind != tyGenericInvokation) or (son.kind != tyGenericInst)) - -proc sonsLen(n: PNode): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc len*(n: PNode): int {.inline.} = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc add*(father, son: PNode) = - if isNil(father.sons): father.sons = @[] - add(father.sons, son) - -proc `[]`*(n: PNode, i: int): PNode {.inline.} = - result = n.sons[i] - -proc newSons(father: PNode, length: int) = - if isNil(father.sons): father.sons = @[] - setlen(father.sons, len(father.sons) + length) - -proc addSon(father, son: PNode) = - if isNil(father.sons): father.sons = @[] - add(father.sons, son) - -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 = - # does not copy its sons! - if src == nil: - return nil - result = newNode(src.kind) - result.info = src.info - result.typ = src.typ - result.flags = src.flags * PersistentNodeFlags - case src.Kind - of nkCharLit..nkInt64Lit: result.intVal = src.intVal - of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal - of nkSym: result.sym = src.sym - of nkIdent: result.ident = src.ident - of nkStrLit..nkTripleStrLit: result.strVal = src.strVal - else: nil - -proc copyTree(src: PNode): PNode = - # copy a whole syntax tree; performs deep copying - if src == nil: - return nil - result = newNode(src.kind) - result.info = src.info - result.typ = src.typ - result.flags = src.flags * PersistentNodeFlags - case src.Kind - of nkCharLit..nkInt64Lit: result.intVal = src.intVal - of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal - of nkSym: result.sym = src.sym - of nkIdent: result.ident = src.ident - of nkStrLit..nkTripleStrLit: result.strVal = src.strVal - else: - result.sons = nil - newSons(result, sonsLen(src)) - for i in countup(0, sonsLen(src) - 1): result.sons[i] = copyTree(src.sons[i]) - -proc lastSon(n: PNode): PNode = - result = n.sons[sonsLen(n) - 1] - -proc lastSon(n: PType): PType = - result = n.sons[sonsLen(n) - 1] - -proc hasSonWith(n: PNode, kind: TNodeKind): bool = - for i in countup(0, sonsLen(n) - 1): - if (n.sons[i] != nil) and (n.sons[i].kind == kind): - return true - result = false - -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] != nil) and (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): - 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: - return false - result = true - -proc addSonIfNotNil(father, n: PNode) = - if n != nil: addSon(father, n) - -proc getInt*(a: PNode): biggestInt = - case a.kind - of nkIntLit..nkInt64Lit: result = a.intVal - else: - internalError(a.info, "getInt") - result = 0 - -proc getFloat*(a: PNode): biggestFloat = - case a.kind - of nkFloatLit..nkFloat64Lit: result = a.floatVal - else: - internalError(a.info, "getFloat") - result = 0.0 - -proc getStr*(a: PNode): string = - case a.kind - of nkStrLit..nkTripleStrLit: result = a.strVal - else: - internalError(a.info, "getStr") - result = "" - -proc getStrOrChar*(a: PNode): string = - case a.kind - of nkStrLit..nkTripleStrLit: result = a.strVal - of nkCharLit: result = chr(int(a.intVal)) & "" - else: - internalError(a.info, "getStrOrChar") - result = "" - -proc mustRehash(length, counter: int): bool = - assert(length > counter) - result = (length * 2 < counter * 3) or (length - counter < 4) - -proc nextTry(h, maxHash: THash): THash = - result = ((5 * h) + 1) and maxHash - # For any initial h in range(maxHash), repeating that maxHash times - # generates each int in range(maxHash) exactly once (see any text on - # random-number generation for proof). - -proc IntSetInit(s: var TIntSet) = - newSeq(s.data, InitIntSetSize) - s.max = InitIntSetSize - 1 - s.counter = 0 - s.head = nil - -proc IntSetGet(t: TIntSet, key: int): PTrunk = - var h = key and t.max - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max) - result = nil - -proc IntSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) = - var h = desc.key and t.max - while data[h] != nil: - assert(data[h] != desc) - h = nextTry(h, t.max) - assert(data[h] == nil) - data[h] = desc - -proc IntSetEnlarge(t: var TIntSet) = - var - n: TTrunkSeq - oldMax: int - oldMax = t.max - t.max = ((t.max + 1) * 2) - 1 - newSeq(n, t.max + 1) - for i in countup(0, oldmax): - if t.data[i] != nil: IntSetRawInsert(t, n, t.data[i]) - swap(t.data, n) - -proc IntSetPut(t: var TIntSet, key: int): PTrunk = - var h = key and t.max - while t.data[h] != nil: - if t.data[h].key == key: - return t.data[h] - h = nextTry(h, t.max) - if mustRehash(t.max + 1, t.counter): IntSetEnlarge(t) - inc(t.counter) - h = key and t.max - while t.data[h] != nil: h = nextTry(h, t.max) - assert(t.data[h] == nil) - new(result) - result.next = t.head - result.key = key - t.head = result - t.data[h] = result - -proc IntSetContains(s: TIntSet, key: int): bool = - var - u: TBitScalar - t: PTrunk - t = IntSetGet(s, `shr`(key, TrunkShift)) - if t != nil: - u = key and TrunkMask - result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 - else: - result = false - -proc IntSetIncl(s: var TIntSet, key: int) = - var - u: TBitScalar - t: PTrunk - t = IntSetPut(s, `shr`(key, TrunkShift)) - u = key and TrunkMask - t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or - `shl`(1, u and IntMask) - -proc IntSetExcl(s: var TIntSet, key: int) = - var - u: TBitScalar - t: PTrunk - t = IntSetGet(s, `shr`(key, TrunkShift)) - if t != nil: - u = key and TrunkMask - t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and - not `shl`(1, u and IntMask) - -proc IntSetContainsOrIncl(s: var TIntSet, key: int): bool = - var - u: TBitScalar - t: PTrunk - t = IntSetGet(s, `shr`(key, TrunkShift)) - if t != nil: - u = key and TrunkMask - result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 - if not result: - t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or - `shl`(1, u and IntMask) - else: - IntSetIncl(s, key) - result = false - -if debugIDs: IntSetInit(usedIds) |