import std/[intsets, tables, algorithm, assertions]
import ast, lineinfos, msgs
type
PackedBoolArray* = object
s: IntSet
len: int
TinyLineInfo* = object
line*: uint16
col*: int16
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
caughtExceptions*: seq[PType]
caughtExceptionsSet*: bool
isDecl*: bool
SuggestFileSymbolDatabase* = object
lineInfo*: seq[TinyLineInfo]
sym*: seq[PSym]
caughtExceptions*: seq[seq[PType]]
caughtExceptionsSet*: PackedBoolArray
isDecl*: PackedBoolArray
fileIndex*: FileIndex
trackCaughtExceptions*: bool
isSorted*: bool
SuggestSymbolDatabase* = Table[FileIndex, SuggestFileSymbolDatabase]
func newPackedBoolArray*(): PackedBoolArray =
PackedBoolArray(
s: initIntSet(),
len: 0
)
func low*(s: PackedBoolArray): int =
0
func high*(s: PackedBoolArray): int =
s.len - 1
func `[]`*(s: PackedBoolArray; idx: int): bool =
s.s.contains(idx)
proc `[]=`*(s: var PackedBoolArray; idx: int; v: bool) =
if v:
s.s.incl(idx)
else:
s.s.excl(idx)
proc add*(s: var PackedBoolArray; v: bool) =
inc(s.len)
if v:
s.s.incl(s.len - 1)
proc reverse*(s: var PackedBoolArray) =
var
reversedSet = initIntSet()
for i in 0..s.high:
if s.s.contains(i):
reversedSet.incl(s.high - i)
s.s = reversedSet
proc getSymInfoPair*(s: SuggestFileSymbolDatabase; idx: int): SymInfoPair =
SymInfoPair(
sym: s.sym[idx],
info: TLineInfo(
line: s.lineInfo[idx].line,
col: s.lineInfo[idx].col,
fileIndex: s.fileIndex
),
caughtExceptions:
if s.trackCaughtExceptions:
s.caughtExceptions[idx]
else:
@[],
caughtExceptionsSet:
if s.trackCaughtExceptions:
s.caughtExceptionsSet[idx]
else:
false,
isDecl: s.isDecl[idx]
)
proc reverse*(s: var SuggestFileSymbolDatabase) =
s.lineInfo.reverse()
s.sym.reverse()
s.caughtExceptions.reverse()
s.caughtExceptionsSet.reverse()
s.isDecl.reverse()
proc newSuggestFileSymbolDatabase*(aFileIndex: FileIndex; aTrackCaughtExceptions: bool): SuggestFileSymbolDatabase =
SuggestFileSymbolDatabase(
lineInfo: @[],
sym: @[],
caughtExceptions: @[],
caughtExceptionsSet: newPackedBoolArray(),
isDecl: newPackedBoolArray(),
fileIndex: aFileIndex,
trackCaughtExceptions: aTrackCaughtExceptions,
isSorted: true
)
proc exactEquals*(a, b: TinyLineInfo): bool =
result = a.line == b.line and a.col == b.col
proc `==`*(a, b: SymInfoPair): bool =
result = a.sym == b.sym and a.info.exactEquals(b.info)
func cmp*(a: TinyLineInfo; b: TinyLineInfo): int =
result = cmp(a.line, b.line)
if result == 0:
result = cmp(a.col, b.col)
func compare*(s: var SuggestFileSymbolDatabase; i, j: int): int =
result = cmp(s.lineInfo[i], s.lineInfo[j])
if result == 0:
result = cmp(s.isDecl[i], s.isDecl[j])
proc exchange(s: var SuggestFileSymbolDatabase; i, j: int) =
if i == j:
return
var tmp1 = s.lineInfo[i]
s.lineInfo[i] = s.lineInfo[j]
s.lineInfo[j] = tmp1
if s.trackCaughtExceptions:
var tmp2 = s.caughtExceptions[i]
s.caughtExceptions[i] = s.caughtExceptions[j]
s.caughtExceptions[j] = tmp2
var tmp3 = s.caughtExceptionsSet[i]
s.caughtExceptionsSet[i] = s.caughtExceptionsSet[j]
s.caughtExceptionsSet[j] = tmp3
var tmp4 = s.isDecl[i]
s.isDecl[i] = s.isDecl[j]
s.isDecl[j] = tmp4
var tmp5 = s.sym[i]
s.sym[i] = s.sym[j]
s.sym[j] = tmp5
proc quickSort(s: var SuggestFileSymbolDatabase; ll, rr: int) =
var
i, j, pivotIdx: int
l = ll
r = rr
while true:
i = l
j = r
pivotIdx = l + ((r - l) shr 1)
while true:
while (i < pivotIdx) and (s.compare(pivotIdx, i) > 0):
inc i
while (j > pivotIdx) and (s.compare(pivotIdx, j) < 0):
dec j
if i < j:
s.exchange(i, j)
if pivotIdx == i:
pivotIdx = j
inc i
elif pivotIdx == j:
pivotIdx = i
dec j
else:
inc i
dec j
else:
break
if (pivotIdx - l) < (r - pivotIdx):
if (l + 1) < pivotIdx:
s.quickSort(l, pivotIdx - 1)
l = pivotIdx + 1
else:
if (pivotIdx + 1) < r:
s.quickSort(pivotIdx + 1, r)
if (l + 1) < pivotIdx:
r = pivotIdx - 1
else:
break
if l >= r:
break
proc sort*(s: var SuggestFileSymbolDatabase) =
s.quickSort(s.lineInfo.low, s.lineInfo.high)
s.isSorted = true
proc add*(s: var SuggestFileSymbolDatabase; v: SymInfoPair) =
doAssert(v.info.fileIndex == s.fileIndex)
s.lineInfo.add(TinyLineInfo(
line: v.info.line,
col: v.info.col
))
s.sym.add(v.sym)
s.isDecl.add(v.isDecl)
if s.trackCaughtExceptions:
s.caughtExceptions.add(v.caughtExceptions)
s.caughtExceptionsSet.add(v.caughtExceptionsSet)
s.isSorted = false
proc add*(s: var SuggestSymbolDatabase; v: SymInfoPair; trackCaughtExceptions: bool) =
s.mgetOrPut(v.info.fileIndex, newSuggestFileSymbolDatabase(v.info.fileIndex, trackCaughtExceptions)).add(v)
proc findSymInfoIndex*(s: var SuggestFileSymbolDatabase; li: TLineInfo): int =
doAssert(li.fileIndex == s.fileIndex)
if not s.isSorted:
s.sort()
var q = TinyLineInfo(
line: li.line,
col: li.col
)
result = binarySearch(s.lineInfo, q, cmp)