mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-05 11:24:08 +00:00
intsets are now a proper module and part of the stdlib
This commit is contained in:
144
compiler/ast.nim
144
compiler/ast.nim
@@ -10,7 +10,7 @@
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, intsets
|
||||
|
||||
const
|
||||
ImportTablePos* = 0
|
||||
@@ -620,39 +620,6 @@ 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
|
||||
|
||||
@@ -663,7 +630,7 @@ var usedIds: TIntSet
|
||||
|
||||
proc registerID(id: PIdObj) =
|
||||
if debugIDs:
|
||||
if (id.id == - 1) or IntSetContainsOrIncl(usedIds, id.id):
|
||||
if (id.id == - 1) or ContainsOrIncl(usedIds, id.id):
|
||||
InternalError("ID already used: " & $(id.id))
|
||||
|
||||
proc getID(): int =
|
||||
@@ -1036,109 +1003,4 @@ proc getStrOrChar*(a: PNode): string =
|
||||
internalError(a.info, "getStrOrChar")
|
||||
result = ""
|
||||
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||
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)
|
||||
if debugIDs: usedIds = InitIntSet()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# the data structures here are used in various places of the compiler.
|
||||
|
||||
import
|
||||
ast, hashes, strutils, options, msgs, ropes, idents, rodutils
|
||||
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
|
||||
|
||||
proc hashNode*(p: PObject): THash
|
||||
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
|
||||
@@ -263,7 +263,7 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif IntSetContainsOrIncl(marker, n.id):
|
||||
elif ContainsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
@@ -284,7 +284,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
if n == nil:
|
||||
result = toRope("null")
|
||||
elif intSetContainsOrIncl(marker, n.id):
|
||||
elif ContainsOrIncl(marker, n.id):
|
||||
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
|
||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
||||
else:
|
||||
@@ -346,18 +346,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
||||
appf(result, "$n$1}", [spaces(indent)])
|
||||
|
||||
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = treeToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = typeToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = symToYamlAux(n, marker, indent, maxRecDepth)
|
||||
|
||||
proc debugType(n: PType): PRope =
|
||||
@@ -612,15 +609,15 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
if result.Name.id == ti.name.id and
|
||||
not IntSetContains(excluding, result.id): break
|
||||
if result.Name.id == ti.name.id and not Contains(excluding, result.id):
|
||||
break
|
||||
h = nextTry(h, high(tab.data))
|
||||
if h == start:
|
||||
result = nil
|
||||
break
|
||||
result = tab.data[h]
|
||||
ti.h = nextTry(h, high(tab.data))
|
||||
if result != nil and IntSetContains(excluding, result.id): result = nil
|
||||
if result != nil and Contains(excluding, result.id): result = nil
|
||||
|
||||
proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
||||
excluding: TIntSet): PSym =
|
||||
|
||||
@@ -709,7 +709,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
assert t.kind == tyObject
|
||||
discard genTypeInfo(p.module, t)
|
||||
var L = lengthOrd(field.typ)
|
||||
if not IntSetContainsOrIncl(p.module.declaredThings, field.id):
|
||||
if not ContainsOrIncl(p.module.declaredThings, field.id):
|
||||
appcg(p.module, cfsVars, "extern $1",
|
||||
discriminatorTableDecl(p.module, t, field))
|
||||
appcg(p, cpsStmts,
|
||||
|
||||
@@ -387,7 +387,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
if t.sym != nil: useHeader(m, t.sym)
|
||||
result = getTypePre(m, t)
|
||||
if result != nil: return
|
||||
if IntSetContainsOrIncl(check, t.id):
|
||||
if ContainsOrIncl(check, t.id):
|
||||
InternalError("cannot generate C type for: " & typeToString(typ))
|
||||
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
||||
# but determining when this needs to be done is hard. We should split
|
||||
@@ -490,8 +490,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||
result = nil
|
||||
|
||||
proc getTypeDesc(m: BModule, typ: PType): PRope =
|
||||
var check: TIntSet
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
result = getTypeDescAux(m, typ, check)
|
||||
|
||||
proc getTypeDesc(m: BModule, magic: string): PRope =
|
||||
@@ -511,10 +510,9 @@ proc finishTypeDescriptions(m: BModule) =
|
||||
proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
var
|
||||
rettype, params: PRope
|
||||
check: TIntSet
|
||||
# using static is needed for inline procs
|
||||
if (prc.typ.callConv == ccInline): result = toRope"static "
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
appf(result, "$1($2, $3)$4",
|
||||
@@ -736,7 +734,7 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
|
||||
else:
|
||||
dataGenerated = true
|
||||
result = ropef("NTI$1", [toRope(id)])
|
||||
if not IntSetContainsOrIncl(m.typeInfoMarker, id):
|
||||
if not ContainsOrIncl(m.typeInfoMarker, id):
|
||||
# declare type information structures:
|
||||
discard cgsym(m, "TNimType")
|
||||
discard cgsym(m, "TNimNode")
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
options,
|
||||
options, intsets,
|
||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||
rodutils
|
||||
@@ -690,12 +690,12 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
if lfNoDecl in sym.loc.Flags: return
|
||||
if lfDynamicLib in sym.loc.Flags:
|
||||
if sym.owner.id != m.module.id and
|
||||
not intSetContainsOrIncl(m.declaredThings, sym.id):
|
||||
not ContainsOrIncl(m.declaredThings, sym.id):
|
||||
appff(m.s[cfsVars], "extern $1 $2;$n",
|
||||
"@$2 = linkonce global $1 zeroinitializer$n",
|
||||
[getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)])
|
||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
elif not IntSetContainsOrIncl(m.declaredProtos, sym.id):
|
||||
elif not ContainsOrIncl(m.declaredProtos, sym.id):
|
||||
appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)])
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
@@ -707,12 +707,12 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
# This also means that a check with ``gGeneratedSyms`` is wrong, we need
|
||||
# a check for ``m.declaredThings``.
|
||||
if not intSetContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
|
||||
if not ContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id):
|
||||
if not ContainsOrIncl(gGeneratedSyms, prc.id):
|
||||
SymInDynamicLib(findPendingModule(m, prc), prc)
|
||||
elif not (sfImportc in prc.flags):
|
||||
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id):
|
||||
if not ContainsOrIncl(gGeneratedSyms, prc.id):
|
||||
genProcAux(findPendingModule(m, prc), prc)
|
||||
|
||||
proc genProc(m: BModule, prc: PSym) =
|
||||
@@ -726,7 +726,7 @@ proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
|
||||
if (lfNoDecl in sym.loc.Flags) or
|
||||
intSetContainsOrIncl(m.declaredThings, sym.id):
|
||||
ContainsOrIncl(m.declaredThings, sym.id):
|
||||
return
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
@@ -748,7 +748,7 @@ proc genConstPrototype(m: BModule, sym: PSym) =
|
||||
if sym.loc.k == locNone:
|
||||
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
|
||||
if (lfNoDecl in sym.loc.Flags) or
|
||||
intSetContainsOrIncl(m.declaredThings, sym.id):
|
||||
ContainsOrIncl(m.declaredThings, sym.id):
|
||||
return
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
@@ -903,14 +903,14 @@ proc genModule(m: BModule, cfilenoext: string): PRope =
|
||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
InitLinkedList(result.headerFiles)
|
||||
intSetInit(result.declaredThings)
|
||||
intSetInit(result.declaredProtos)
|
||||
result.declaredThings = initIntSet()
|
||||
result.declaredProtos = initIntSet()
|
||||
result.cfilename = filename
|
||||
result.filename = filename
|
||||
initIdTable(result.typeCache)
|
||||
initIdTable(result.forwTypeCache)
|
||||
result.module = module
|
||||
intSetInit(result.typeInfoMarker)
|
||||
result.typeInfoMarker = initIntSet()
|
||||
result.initProc = newProc(nil, result)
|
||||
result.initProc.options = gOptions
|
||||
initNodeTable(result.dataCache)
|
||||
@@ -1037,4 +1037,4 @@ proc cgenPass(): TPass =
|
||||
result.close = myClose
|
||||
|
||||
InitIiTable(gToTypeInfoId)
|
||||
IntSetInit(gGeneratedSyms)
|
||||
gGeneratedSyms = initIntSet()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## This module implements code generation for multi methods.
|
||||
|
||||
import
|
||||
options, ast, astalgo, msgs, idents, renderer, types, magicsys
|
||||
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys
|
||||
|
||||
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
var dest = skipTypes(d, abstractPtrs)
|
||||
@@ -95,7 +95,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||
result = 0
|
||||
for col in countup(1, sonsLen(a.typ) - 1):
|
||||
if intSetContains(relevantCols, col):
|
||||
if Contains(relevantCols, col):
|
||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||
var bb = skipTypes(b.typ.sons[col], skipPtrs)
|
||||
var d = inheritanceDiff(aa, bb)
|
||||
@@ -132,7 +132,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
|
||||
var curr = methods[meth] # generate condition:
|
||||
var cond: PNode = nil
|
||||
for col in countup(1, paramLen - 1):
|
||||
if IntSetContains(relevantCols, col):
|
||||
if Contains(relevantCols, col):
|
||||
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
addSon(isn, newSymNode(iss))
|
||||
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
|
||||
@@ -169,12 +169,11 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
|
||||
result.ast.sons[codePos] = disp
|
||||
|
||||
proc generateMethodDispatchers*(): PNode =
|
||||
var relevantCols: TIntSet
|
||||
result = newNode(nkStmtList)
|
||||
for bucket in countup(0, len(gMethods) - 1):
|
||||
IntSetInit(relevantCols)
|
||||
var relevantCols = initIntSet()
|
||||
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
|
||||
if relevantCol(gMethods[bucket], col): IntSetIncl(relevantCols, col)
|
||||
if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
|
||||
sortBucket(gMethods[bucket], relevantCols)
|
||||
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
import
|
||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils
|
||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
||||
intsets
|
||||
|
||||
proc ecmasgenPass*(): TPass
|
||||
# implementation
|
||||
@@ -67,7 +68,7 @@ type
|
||||
|
||||
proc newGlobals(): PGlobals =
|
||||
new(result)
|
||||
IntSetInit(result.typeInfoGenerated)
|
||||
result.typeInfoGenerated = initIntSet()
|
||||
|
||||
proc initCompRes(r: var TCompRes) =
|
||||
r.com = nil
|
||||
@@ -228,7 +229,7 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope =
|
||||
var t = typ
|
||||
if t.kind == tyGenericInst: t = lastSon(t)
|
||||
result = ropef("NTI$1", [toRope(t.id)])
|
||||
if IntSetContainsOrIncl(p.globals.TypeInfoGenerated, t.id): return
|
||||
if ContainsOrIncl(p.globals.TypeInfoGenerated, t.id): return
|
||||
case t.kind
|
||||
of tyDistinct:
|
||||
result = genTypeInfo(p, typ.sons[0])
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
# This module implements the symbol importing mechanism.
|
||||
|
||||
import
|
||||
strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, semdata,
|
||||
passes
|
||||
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
|
||||
semdata, passes
|
||||
|
||||
proc evalImport*(c: PContext, n: PNode): PNode
|
||||
proc evalFrom*(c: PContext, n: PNode): PNode
|
||||
@@ -45,8 +45,8 @@ proc rawImportSymbol(c: PContext, s: PSym) =
|
||||
if (check != nil) and (check.id != copy.id):
|
||||
if not (s.kind in OverloadableSyms):
|
||||
# s and check need to be qualified:
|
||||
IntSetIncl(c.AmbiguousSymbols, copy.id)
|
||||
IntSetIncl(c.AmbiguousSymbols, check.id)
|
||||
Incl(c.AmbiguousSymbols, copy.id)
|
||||
Incl(c.AmbiguousSymbols, check.id)
|
||||
StrTableAdd(c.tab.stack[importTablePos], copy)
|
||||
if s.kind == skType:
|
||||
var etyp = s.typ
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
# This module implements lookup helpers.
|
||||
|
||||
import
|
||||
ast, astalgo, idents, semdata, types, msgs, options, rodread, renderer
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||
renderer
|
||||
|
||||
proc considerAcc*(n: PNode): PIdent =
|
||||
case n.kind
|
||||
@@ -115,7 +116,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||
result = SymtabGet(c.Tab, ident)
|
||||
if result == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
else: InternalError(n.info, "lookUp")
|
||||
if IntSetContains(c.AmbiguousSymbols, result.id):
|
||||
if Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, result.name.s)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
|
||||
@@ -131,12 +132,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||
if result == nil and checkUndeclared in flags:
|
||||
GlobalError(n.info, errUndeclaredIdentifier, ident.s)
|
||||
elif checkAmbiguity in flags and result != nil and
|
||||
IntSetContains(c.AmbiguousSymbols, result.id):
|
||||
Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, ident.s)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
if checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols,
|
||||
result.id):
|
||||
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
|
||||
LocalError(n.info, errUseQualifier, n.sym.name.s)
|
||||
of nkDotExpr:
|
||||
result = nil
|
||||
@@ -197,8 +197,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
o.mode = oimSymChoice
|
||||
result = n.sons[0].sym
|
||||
o.stackPtr = 1
|
||||
IntSetInit(o.inSymChoice)
|
||||
IntSetIncl(o.inSymChoice, result.id)
|
||||
o.inSymChoice = initIntSet()
|
||||
Incl(o.inSymChoice, result.id)
|
||||
else: nil
|
||||
if result != nil and result.kind == skStub: loadStub(result)
|
||||
|
||||
@@ -223,7 +223,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
of oimSymChoice:
|
||||
if o.stackPtr < sonsLen(n):
|
||||
result = n.sons[o.stackPtr].sym
|
||||
IntSetIncl(o.inSymChoice, result.id)
|
||||
Incl(o.inSymChoice, result.id)
|
||||
inc(o.stackPtr)
|
||||
else:
|
||||
# try 'local' symbols too for Koenig's lookup:
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
# writing of rod files is split into two different modules.
|
||||
|
||||
import
|
||||
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
||||
ropes, idents, crc, rodread, passes, importer
|
||||
intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
|
||||
condsyms, ropes, idents, crc, rodread, passes, importer
|
||||
|
||||
proc rodwritePass*(): TPass
|
||||
# implementation
|
||||
@@ -446,4 +446,4 @@ proc rodwritePass(): TPass =
|
||||
result.close = myClose
|
||||
result.process = process
|
||||
|
||||
IntSetInit(debugWritten)
|
||||
debugWritten= initIntSet()
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||
magicsys, parser, nversion, nimsets, semdata, evals, semfold, importer,
|
||||
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
|
||||
semthreads
|
||||
semthreads, intsets
|
||||
|
||||
proc semPass*(): TPass
|
||||
# implementation
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
# This module contains the data structures for the semantic checking phase.
|
||||
|
||||
import
|
||||
strutils, lists, options, lexer, ast, astalgo, trees, treetab, wordrecg,
|
||||
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||
wordrecg,
|
||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||
magicsys, nversion, nimsets, parser, times, passes, rodread
|
||||
|
||||
@@ -118,7 +119,7 @@ proc newOptionEntry(): POptionEntry =
|
||||
proc newContext(module: PSym, nimfile: string): PContext =
|
||||
new(result)
|
||||
InitSymTab(result.tab)
|
||||
IntSetInit(result.AmbiguousSymbols)
|
||||
result.AmbiguousSymbols = initIntset()
|
||||
initLinkedList(result.optionStack)
|
||||
initLinkedList(result.libs)
|
||||
append(result.optionStack, newOptionEntry())
|
||||
@@ -127,7 +128,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||
result.threadEntries = newNode(nkStmtList)
|
||||
result.converters = @[]
|
||||
result.filename = nimfile
|
||||
IntSetInit(result.includedFiles)
|
||||
result.includedFiles = initIntSet()
|
||||
initStrTable(result.userPragmas)
|
||||
|
||||
proc addConverter(c: PContext, conv: PSym) =
|
||||
|
||||
@@ -888,11 +888,10 @@ proc checkPar(n: PNode): TParKind =
|
||||
return paNone
|
||||
|
||||
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
||||
var ids: TIntSet
|
||||
result = newNodeI(nkPar, n.info)
|
||||
var typ = newTypeS(tyTuple, c)
|
||||
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
||||
IntSetInit(ids)
|
||||
var ids = initIntSet()
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind != nkExprColonExpr) or
|
||||
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
|
||||
@@ -900,7 +899,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): 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 IntSetContainsOrIncl(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])
|
||||
var f = newSymS(skField, n.sons[i].sons[0], c)
|
||||
|
||||
@@ -476,11 +476,10 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||
localError(n.info, errExprCannotBeRaised)
|
||||
|
||||
proc semTry(c: PContext, n: PNode): PNode =
|
||||
var check: TIntSet
|
||||
result = n
|
||||
checkMinSonsLen(n, 2)
|
||||
n.sons[0] = semStmtScope(c, n.sons[0])
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
checkMinSonsLen(a, 1)
|
||||
@@ -493,7 +492,7 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||
GlobalError(a.sons[j].info, errExprCannotBeRaised)
|
||||
a.sons[j] = newNodeI(nkType, a.sons[j].info)
|
||||
a.sons[j].typ = typ
|
||||
if IntSetContainsOrIncl(check, typ.id):
|
||||
if ContainsOrIncl(check, typ.id):
|
||||
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
||||
elif a.kind != nkFinally:
|
||||
illFormedAst(n)
|
||||
@@ -820,10 +819,10 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var f = getModuleFile(n.sons[i])
|
||||
var fileIndex = includeFilename(f)
|
||||
if IntSetContainsOrIncl(c.includedFiles, fileIndex):
|
||||
if ContainsOrIncl(c.includedFiles, fileIndex):
|
||||
GlobalError(n.info, errRecursiveDependencyX, f)
|
||||
addSon(result, semStmt(c, gIncludeFile(f)))
|
||||
IntSetExcl(c.includedFiles, fileIndex)
|
||||
Excl(c.includedFiles, fileIndex)
|
||||
|
||||
proc SemStmt(c: PContext, n: PNode): PNode =
|
||||
const # must be last statements in a block:
|
||||
|
||||
@@ -117,7 +117,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
|
||||
var s: PSym
|
||||
case n.kind
|
||||
of nkIdent:
|
||||
if not withinBind and not IntSetContains(toBind, n.ident.id):
|
||||
if not withinBind and not Contains(toBind, n.ident.id):
|
||||
s = SymTabLocalGet(c.Tab, n.ident)
|
||||
if (s != nil):
|
||||
result = newSymNode(s)
|
||||
@@ -125,7 +125,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
IntSetIncl(toBind, n.ident.id)
|
||||
Incl(toBind, n.ident.id)
|
||||
result = symChoice(c, n, lookup(c, n))
|
||||
of nkEmpty, nkSym..nkNilLit: # atom
|
||||
result = n
|
||||
@@ -160,7 +160,6 @@ proc transformToExpr(n: PNode): PNode =
|
||||
proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
var
|
||||
s: PSym
|
||||
toBind: TIntSet
|
||||
if c.p.owner.kind == skModule:
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {sfStar})
|
||||
incl(s.flags, sfGlobal)
|
||||
@@ -189,7 +188,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
s.typ.sons[0] = newTypeS(tyStmt, c)
|
||||
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
|
||||
addParams(c, s.typ.n) # resolve parameters:
|
||||
IntSetInit(toBind)
|
||||
var toBind = initIntSet()
|
||||
n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind)
|
||||
if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}):
|
||||
n.sons[codePos] = transformToExpr(n.sons[codePos])
|
||||
|
||||
@@ -192,10 +192,9 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
var
|
||||
typ: PType
|
||||
check: TIntSet
|
||||
result = newOrPrevType(tyTuple, prev, c)
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
@@ -212,7 +211,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
field.typ = typ
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
if IntSetContainsOrIncl(check, field.name.id):
|
||||
if ContainsOrIncl(check, field.name.id):
|
||||
GlobalError(a.sons[j].info, errAttemptToRedefine, field.name.s)
|
||||
addSon(result.n, newSymNode(field))
|
||||
addSon(result, typ)
|
||||
@@ -396,7 +395,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||
f.loc.r = toRope(f.name.s)
|
||||
f.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags)
|
||||
inc(pos)
|
||||
if IntSetContainsOrIncl(check, f.name.id):
|
||||
if ContainsOrIncl(check, f.name.id):
|
||||
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
|
||||
if a.kind == nkEmpty: addSon(father, newSymNode(f))
|
||||
else: addSon(a, newSymNode(f))
|
||||
@@ -419,7 +418,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
addInheritedFieldsAux(c, check, pos, n.sons[i])
|
||||
of nkSym:
|
||||
IntSetIncl(check, n.sym.name.id)
|
||||
Incl(check, n.sym.name.id)
|
||||
inc(pos)
|
||||
else: InternalError(n.info, "addInheritedFieldsAux()")
|
||||
|
||||
@@ -437,8 +436,7 @@ proc skipGenericInvokation(t: PType): PType {.inline.} =
|
||||
result = lastSon(result)
|
||||
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
var check: TIntSet
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
var pos = 0
|
||||
var base: PType = nil
|
||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||
@@ -460,7 +458,7 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
|
||||
cl: var TIntSet): PType =
|
||||
result = t
|
||||
if t == nil: return
|
||||
if IntSetContainsOrIncl(cl, t.id): return
|
||||
if ContainsOrIncl(cl, t.id): return
|
||||
case t.kind
|
||||
of tyGenericBody:
|
||||
#debug(t)
|
||||
@@ -470,7 +468,7 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
|
||||
if t.sons[i].kind != tyGenericParam:
|
||||
InternalError("addTypeVarsOfGenericBody")
|
||||
# do not declare ``TKey`` twice:
|
||||
#if not IntSetContainsOrIncl(cl, t.sons[i].sym.ident.id):
|
||||
#if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
|
||||
var s = copySym(t.sons[i].sym)
|
||||
s.position = sonsLen(genericParams)
|
||||
if s.typ == nil or s.typ.kind != tyGenericParam:
|
||||
@@ -501,16 +499,17 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
var
|
||||
def, res: PNode
|
||||
typ: PType
|
||||
check, cl: TIntSet
|
||||
cl: TIntSet
|
||||
checkMinSonsLen(n, 1)
|
||||
result = newOrPrevType(tyProc, prev, c)
|
||||
result.callConv = lastOptionEntry(c).defaultCC
|
||||
result.n = newNodeI(nkFormalParams, n.info)
|
||||
if (genericParams != nil) and (sonsLen(genericParams) == 0): IntSetInit(cl)
|
||||
if (genericParams != nil) and (sonsLen(genericParams) == 0):
|
||||
cl = initIntSet()
|
||||
addSon(result, nil) # return type
|
||||
res = newNodeI(nkType, n.info)
|
||||
addSon(result.n, res)
|
||||
IntSetInit(check)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
@@ -539,7 +538,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
arg.position = counter
|
||||
inc(counter)
|
||||
if def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||
if IntSetContainsOrIncl(check, arg.name.id):
|
||||
if ContainsOrIncl(check, arg.name.id):
|
||||
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||
addSon(result.n, newSymNode(arg))
|
||||
addSon(result, typ)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# the call to overloaded procs, generic procs and operators.
|
||||
|
||||
import
|
||||
ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys
|
||||
|
||||
type
|
||||
@@ -608,7 +608,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
|
||||
# no error message!
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if IntSetContainsOrIncl(marker, formal.position):
|
||||
if ContainsOrIncl(marker, formal.position):
|
||||
# already in namedParams:
|
||||
LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
@@ -653,7 +653,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
|
||||
if m.callee.n.sons[f].kind != nkSym:
|
||||
InternalError(n.sons[a].info, "matches")
|
||||
formal = m.callee.n.sons[f].sym
|
||||
if IntSetContainsOrIncl(marker, formal.position):
|
||||
if ContainsOrIncl(marker, formal.position):
|
||||
# already in namedParams:
|
||||
LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
@@ -677,20 +677,18 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
|
||||
|
||||
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) =
|
||||
# for 'suggest' support:
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = initIntSet()
|
||||
matchesAux(c, n, m, marker)
|
||||
|
||||
proc matches*(c: PContext, n: PNode, m: var TCandidate) =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = initIntSet()
|
||||
matchesAux(c, n, m, marker)
|
||||
if m.state == csNoMatch: return
|
||||
# check that every formal parameter got a value:
|
||||
var f = 1
|
||||
while f < sonsLen(m.callee.n):
|
||||
var formal = m.callee.n.sons[f].sym
|
||||
if not IntSetContainsOrIncl(marker, formal.position):
|
||||
if not ContainsOrIncl(marker, formal.position):
|
||||
if formal.ast == nil:
|
||||
if formal.typ.kind == tyOpenArray:
|
||||
var container = newNodeI(nkBracket, n.info)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# * introduces method dispatchers
|
||||
|
||||
import
|
||||
strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, passes, semfold, magicsys, cgmeth
|
||||
|
||||
const
|
||||
@@ -528,8 +528,7 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
|
||||
of skVar: found = not (sfGlobal in s.flags)
|
||||
of skTemp, skForVar, skParam: found = true
|
||||
else: nil
|
||||
if found and (owner.id != s.owner.id) and
|
||||
not IntSetContainsOrIncl(marked, s.id):
|
||||
if found and (owner.id != s.owner.id) and not ContainsOrIncl(marked, s.id):
|
||||
incl(s.flags, sfInClosure)
|
||||
addSon(container, copyNode(n)) # DON'T make a copy of the symbol!
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||
@@ -555,9 +554,8 @@ proc indirectAccess(a, b: PSym): PNode =
|
||||
result.typ = y.typ
|
||||
|
||||
proc transformLambda(c: PTransf, n: PNode): PNode =
|
||||
var marked: TIntSet
|
||||
var marked = initIntSet()
|
||||
result = n
|
||||
IntSetInit(marked)
|
||||
if (n.sons[namePos].kind != nkSym): InternalError(n.info, "transformLambda")
|
||||
var s = n.sons[namePos].sym
|
||||
var closure = newNodeI(nkRecList, n.sons[codePos].info)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# this module contains routines for accessing and iterating over types
|
||||
|
||||
import
|
||||
ast, astalgo, trees, msgs, strutils, platform
|
||||
intsets, ast, astalgo, trees, msgs, strutils, platform
|
||||
|
||||
proc firstOrd*(t: PType): biggestInt
|
||||
proc lastOrd*(t: PType): biggestInt
|
||||
@@ -219,7 +219,7 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
|
||||
if t == nil: return
|
||||
result = iter(t, closure)
|
||||
if result: return
|
||||
if not IntSetContainsOrIncl(marker, t.id):
|
||||
if not ContainsOrIncl(marker, t.id):
|
||||
case t.kind
|
||||
of tyGenericInst, tyGenericBody:
|
||||
result = iterOverTypeAux(marker, lastSon(t), iter, closure)
|
||||
@@ -230,8 +230,7 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
|
||||
if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
|
||||
|
||||
proc IterOverType(t: PType, iter: TTypeIter, closure: PObject): bool =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = iterOverTypeAux(marker, t, iter, closure)
|
||||
|
||||
proc searchTypeForAux(t: PType, predicate: TTypePredicate,
|
||||
@@ -263,7 +262,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet):
|
||||
# iterates over VALUE types!
|
||||
result = false
|
||||
if t == nil: return
|
||||
if IntSetContainsOrIncl(marker, t.id): return
|
||||
if ContainsOrIncl(marker, t.id): return
|
||||
result = Predicate(t)
|
||||
if result: return
|
||||
case t.kind
|
||||
@@ -280,8 +279,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet):
|
||||
nil
|
||||
|
||||
proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = searchTypeForAux(t, predicate, marker)
|
||||
|
||||
proc isObjectPredicate(t: PType): bool =
|
||||
@@ -322,8 +320,7 @@ proc analyseObjectWithTypeFieldAux(t: PType, marker: var TIntSet): TTypeFieldRes
|
||||
nil
|
||||
|
||||
proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = analyseObjectWithTypeFieldAux(t, marker)
|
||||
|
||||
proc isGBCRef(t: PType): bool =
|
||||
@@ -365,7 +362,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
|
||||
if tfAcyclic in t.flags: return
|
||||
case t.kind
|
||||
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray:
|
||||
if not IntSetContainsOrIncl(marker, t.id):
|
||||
if not ContainsOrIncl(marker, t.id):
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
result = canFormAcycleAux(marker, t.sons[i], startId)
|
||||
if result: return
|
||||
@@ -376,8 +373,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
|
||||
nil
|
||||
|
||||
proc canFormAcycle(typ: PType): bool =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = canFormAcycleAux(marker, typ, typ.id)
|
||||
|
||||
proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
|
||||
@@ -400,7 +396,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
|
||||
result = nil
|
||||
if t == nil: return
|
||||
result = iter(t, closure)
|
||||
if not IntSetContainsOrIncl(marker, t.id):
|
||||
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 (result.sons[i] == nil) and (result.kind == tyGenericInst):
|
||||
@@ -409,8 +405,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
|
||||
assert(result != nil)
|
||||
|
||||
proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = mutateTypeAux(marker, t, iter, closure)
|
||||
|
||||
proc rangeToStr(n: PNode): string =
|
||||
@@ -591,17 +586,14 @@ proc equalParam(a, b: PSym): TParamsEquality =
|
||||
result = paramsNotEqual
|
||||
|
||||
proc equalParams(a, b: PNode): TParamsEquality =
|
||||
var
|
||||
length: int
|
||||
m, n: PSym
|
||||
result = paramsEqual
|
||||
length = sonsLen(a)
|
||||
var length = sonsLen(a)
|
||||
if length != sonsLen(b):
|
||||
result = paramsNotEqual
|
||||
else:
|
||||
for i in countup(1, length - 1):
|
||||
m = a.sons[i].sym
|
||||
n = b.sons[i].sym
|
||||
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:
|
||||
@@ -646,7 +638,6 @@ proc sameTuple(a, b: PType, DistinctOf: bool): 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.
|
||||
var x, y: PSym
|
||||
if sonsLen(a) == sonsLen(b):
|
||||
result = true
|
||||
for i in countup(0, sonsLen(a) - 1):
|
||||
@@ -658,8 +649,8 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool =
|
||||
# check field names:
|
||||
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
|
||||
if b.n.sons[i].kind != nkSym: InternalError(b.n.info, "sameTuple")
|
||||
x = a.n.sons[i].sym
|
||||
y = b.n.sons[i].sym
|
||||
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
|
||||
else:
|
||||
@@ -758,17 +749,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
||||
if not result: return
|
||||
|
||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||
var t, t2: PType
|
||||
assert(kind in {skVar, skConst, skParam})
|
||||
# if we have already checked the type, return true, because we stop the
|
||||
# evaluation if something is wrong:
|
||||
result = true
|
||||
if typ == nil:
|
||||
return # if we have already checked the type, return true, because we stop the
|
||||
# evaluation if something is wrong:
|
||||
if IntSetContainsOrIncl(marker, typ.id): return
|
||||
t = skipTypes(typ, abstractInst)
|
||||
if typ == nil: return
|
||||
if ContainsOrIncl(marker, typ.id): return
|
||||
var t = skipTypes(typ, abstractInst)
|
||||
case t.kind
|
||||
of tyVar:
|
||||
t2 = skipTypes(t.sons[0], abstractInst)
|
||||
var t2 = skipTypes(t.sons[0], abstractInst)
|
||||
case t2.kind
|
||||
of tyVar:
|
||||
result = false # ``var var`` is always an invalid type:
|
||||
@@ -815,8 +805,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||
if t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
|
||||
|
||||
proc typeAllowed(t: PType, kind: TSymKind): bool =
|
||||
var marker: TIntSet
|
||||
IntSetInit(marker)
|
||||
var marker = InitIntSet()
|
||||
result = typeAllowedAux(marker, t, kind)
|
||||
|
||||
proc align(address, alignment: biggestInt): biggestInt =
|
||||
|
||||
@@ -42,6 +42,9 @@ Core
|
||||
Contains procs for serialization and deseralization of arbitrary Nimrod
|
||||
data structures.
|
||||
|
||||
* `typeinfo <typeinfo.html>`_
|
||||
Provides (unsafe) access to Nimrod's run time type information.
|
||||
|
||||
|
||||
Collections and algorithms
|
||||
--------------------------
|
||||
@@ -53,7 +56,9 @@ Collections and algorithms
|
||||
* `lists <lists.html>`_
|
||||
Nimrod linked list support. Contains singly and doubly linked lists and
|
||||
circular lists ("rings").
|
||||
|
||||
* `intsets <intsets.html>`_
|
||||
Efficient implementation of a set of ints as a sparse bit set.
|
||||
|
||||
|
||||
String handling
|
||||
---------------
|
||||
|
||||
177
lib/pure/collections/intsets.nim
Normal file
177
lib/pure/collections/intsets.nim
Normal file
@@ -0,0 +1,177 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## The ``intsets`` module implements an efficient int set implemented as a
|
||||
## sparse bit set.
|
||||
## **Note**: Since Nimrod does not allow the assignment operator to be
|
||||
## overloaded, ``=`` for int sets performs some rather meaningless shallow
|
||||
## copy.
|
||||
|
||||
import
|
||||
os, hashes, math
|
||||
|
||||
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 ## an efficient set of 'int' implemented as a
|
||||
## sparse bit set
|
||||
counter, max: int
|
||||
head: PTrunk
|
||||
data: TTrunkSeq
|
||||
|
||||
proc mustRehash(length, counter: int): bool {.inline.} =
|
||||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc nextTry(h, maxHash: THash): THash {.inline.} =
|
||||
result = ((5 * h) + 1) and maxHash
|
||||
|
||||
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
|
||||
var 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 contains*(s: TIntSet, key: int): bool =
|
||||
## returns true iff `key` is in `s`.
|
||||
var t = IntSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
var u = key and TrunkMask
|
||||
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc incl*(s: var TIntSet, key: int) =
|
||||
## includes an element `key` in `s`.
|
||||
var t = IntSetPut(s, `shr`(key, TrunkShift))
|
||||
var u = key and TrunkMask
|
||||
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
|
||||
`shl`(1, u and IntMask)
|
||||
|
||||
proc excl*(s: var TIntSet, key: int) =
|
||||
## excludes `key` from the set `s`.
|
||||
var t = IntSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
var u = key and TrunkMask
|
||||
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
|
||||
not `shl`(1, u and IntMask)
|
||||
|
||||
proc containsOrIncl*(s: var TIntSet, key: int): bool =
|
||||
## returns true if `s` contains `key`, otherwise `key` is included in `s`
|
||||
## and false is returned.
|
||||
var t = IntSetGet(s, `shr`(key, TrunkShift))
|
||||
if t != nil:
|
||||
var 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:
|
||||
incl(s, key)
|
||||
result = false
|
||||
|
||||
proc initIntSet*: TIntSet =
|
||||
## creates a new int set that is empty.
|
||||
newSeq(result.data, InitIntSetSize)
|
||||
result.max = InitIntSetSize-1
|
||||
result.counter = 0
|
||||
result.head = nil
|
||||
|
||||
template dollarImpl(): stmt =
|
||||
result = "{"
|
||||
for key in items(s):
|
||||
if result.len > 1: result.add(", ")
|
||||
result.add($key)
|
||||
result.add("}")
|
||||
|
||||
proc `$`*(s: TIntSet): string =
|
||||
## The `$` operator for int sets.
|
||||
dollarImpl()
|
||||
|
||||
iterator items*(s: TIntSet): int {.inline.} =
|
||||
## iterates over any included element of `s`.
|
||||
var r = s.head
|
||||
while r != nil:
|
||||
var i = 0
|
||||
while i <= high(r.bits):
|
||||
var w = r.bits[i]
|
||||
# taking a copy of r.bits[i] here is correct, because
|
||||
# modifying operations are not allowed during traversation
|
||||
var j = 0
|
||||
while w != 0: # test all remaining bits for zero
|
||||
if (w and 1) != 0: # the bit is set!
|
||||
yield (r.key shl TrunkShift) or (i shl IntShift +% j)
|
||||
inc(j)
|
||||
w = w shr 1
|
||||
inc(i)
|
||||
r = r.next
|
||||
|
||||
when isMainModule:
|
||||
var x = initIntSet()
|
||||
x.incl(1)
|
||||
x.incl(2)
|
||||
x.incl(7)
|
||||
x.incl(1056)
|
||||
for e in items(x): echo e
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2006 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
2
todo.txt
2
todo.txt
@@ -78,7 +78,7 @@ Low priority
|
||||
Library
|
||||
-------
|
||||
|
||||
- specialized bit sets; specialized string sets
|
||||
- radix tree for strings; maybe suffix tree
|
||||
- locale support
|
||||
- conversion between character sets
|
||||
- bignums
|
||||
|
||||
@@ -51,6 +51,7 @@ Additions
|
||||
- Added ``lists`` module which contains generic linked lists.
|
||||
- Added ``sets`` module which contains generic hash sets.
|
||||
- Added ``tables`` module which contains generic hash tables.
|
||||
- Added ``intsets`` module which contains a specialized int set data type.
|
||||
- Added ``scgi`` module.
|
||||
- Added ``smtp`` module.
|
||||
- Added ``re.findAll``, ``pegs.findAll``.
|
||||
|
||||
@@ -24,7 +24,7 @@ file: ticker
|
||||
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview"
|
||||
doc: "tools;c2nim;niminst"
|
||||
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst"
|
||||
srcdoc: "core/macros;core/marshal"
|
||||
srcdoc: "core/macros;core/marshal;core/typeinfo"
|
||||
srcdoc: "impure/graphics;pure/sockets"
|
||||
srcdoc: "system.nim;system/threads.nim;pure/os;pure/strutils;pure/math"
|
||||
srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
|
||||
@@ -39,6 +39,7 @@ srcdoc: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors"
|
||||
srcdoc: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
|
||||
srcdoc: "impure/rdstdin;wrappers/zmq"
|
||||
srcdoc: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
|
||||
srcdoc: "pure/collections/intsets"
|
||||
|
||||
webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup"
|
||||
webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"
|
||||
|
||||
Reference in New Issue
Block a user