suggestsymdb.nim 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import std/[intsets, tables, algorithm, assertions]
  2. import ast, lineinfos, msgs
  3. type
  4. PackedBoolArray* = object
  5. s: IntSet
  6. len: int
  7. TinyLineInfo* = object
  8. line*: uint16
  9. col*: int16
  10. SymInfoPair* = object
  11. sym*: PSym
  12. info*: TLineInfo
  13. caughtExceptions*: seq[PType]
  14. caughtExceptionsSet*: bool
  15. isDecl*: bool
  16. SuggestFileSymbolDatabase* = object
  17. lineInfo*: seq[TinyLineInfo]
  18. sym*: seq[PSym]
  19. caughtExceptions*: seq[seq[PType]]
  20. caughtExceptionsSet*: PackedBoolArray
  21. isDecl*: PackedBoolArray
  22. fileIndex*: FileIndex
  23. trackCaughtExceptions*: bool
  24. isSorted*: bool
  25. SuggestSymbolDatabase* = Table[FileIndex, SuggestFileSymbolDatabase]
  26. func newPackedBoolArray*(): PackedBoolArray =
  27. PackedBoolArray(
  28. s: initIntSet(),
  29. len: 0
  30. )
  31. func low*(s: PackedBoolArray): int =
  32. 0
  33. func high*(s: PackedBoolArray): int =
  34. s.len - 1
  35. func `[]`*(s: PackedBoolArray; idx: int): bool =
  36. s.s.contains(idx)
  37. proc `[]=`*(s: var PackedBoolArray; idx: int; v: bool) =
  38. if v:
  39. s.s.incl(idx)
  40. else:
  41. s.s.excl(idx)
  42. proc add*(s: var PackedBoolArray; v: bool) =
  43. inc(s.len)
  44. if v:
  45. s.s.incl(s.len - 1)
  46. proc reverse*(s: var PackedBoolArray) =
  47. var
  48. reversedSet = initIntSet()
  49. for i in 0..s.high:
  50. if s.s.contains(i):
  51. reversedSet.incl(s.high - i)
  52. s.s = reversedSet
  53. proc getSymInfoPair*(s: SuggestFileSymbolDatabase; idx: int): SymInfoPair =
  54. SymInfoPair(
  55. sym: s.sym[idx],
  56. info: TLineInfo(
  57. line: s.lineInfo[idx].line,
  58. col: s.lineInfo[idx].col,
  59. fileIndex: s.fileIndex
  60. ),
  61. caughtExceptions:
  62. if s.trackCaughtExceptions:
  63. s.caughtExceptions[idx]
  64. else:
  65. @[],
  66. caughtExceptionsSet:
  67. if s.trackCaughtExceptions:
  68. s.caughtExceptionsSet[idx]
  69. else:
  70. false,
  71. isDecl: s.isDecl[idx]
  72. )
  73. proc reverse*(s: var SuggestFileSymbolDatabase) =
  74. s.lineInfo.reverse()
  75. s.sym.reverse()
  76. s.caughtExceptions.reverse()
  77. s.caughtExceptionsSet.reverse()
  78. s.isDecl.reverse()
  79. proc newSuggestFileSymbolDatabase*(aFileIndex: FileIndex; aTrackCaughtExceptions: bool): SuggestFileSymbolDatabase =
  80. SuggestFileSymbolDatabase(
  81. lineInfo: @[],
  82. sym: @[],
  83. caughtExceptions: @[],
  84. caughtExceptionsSet: newPackedBoolArray(),
  85. isDecl: newPackedBoolArray(),
  86. fileIndex: aFileIndex,
  87. trackCaughtExceptions: aTrackCaughtExceptions,
  88. isSorted: true
  89. )
  90. proc exactEquals*(a, b: TinyLineInfo): bool =
  91. result = a.line == b.line and a.col == b.col
  92. proc `==`*(a, b: SymInfoPair): bool =
  93. result = a.sym == b.sym and a.info.exactEquals(b.info)
  94. func cmp*(a: TinyLineInfo; b: TinyLineInfo): int =
  95. result = cmp(a.line, b.line)
  96. if result == 0:
  97. result = cmp(a.col, b.col)
  98. func compare*(s: var SuggestFileSymbolDatabase; i, j: int): int =
  99. result = cmp(s.lineInfo[i], s.lineInfo[j])
  100. if result == 0:
  101. result = cmp(s.isDecl[i], s.isDecl[j])
  102. proc exchange(s: var SuggestFileSymbolDatabase; i, j: int) =
  103. if i == j:
  104. return
  105. var tmp1 = s.lineInfo[i]
  106. s.lineInfo[i] = s.lineInfo[j]
  107. s.lineInfo[j] = tmp1
  108. if s.trackCaughtExceptions:
  109. var tmp2 = s.caughtExceptions[i]
  110. s.caughtExceptions[i] = s.caughtExceptions[j]
  111. s.caughtExceptions[j] = tmp2
  112. var tmp3 = s.caughtExceptionsSet[i]
  113. s.caughtExceptionsSet[i] = s.caughtExceptionsSet[j]
  114. s.caughtExceptionsSet[j] = tmp3
  115. var tmp4 = s.isDecl[i]
  116. s.isDecl[i] = s.isDecl[j]
  117. s.isDecl[j] = tmp4
  118. var tmp5 = s.sym[i]
  119. s.sym[i] = s.sym[j]
  120. s.sym[j] = tmp5
  121. proc quickSort(s: var SuggestFileSymbolDatabase; ll, rr: int) =
  122. var
  123. i, j, pivotIdx: int
  124. l = ll
  125. r = rr
  126. while true:
  127. i = l
  128. j = r
  129. pivotIdx = l + ((r - l) shr 1)
  130. while true:
  131. while (i < pivotIdx) and (s.compare(pivotIdx, i) > 0):
  132. inc i
  133. while (j > pivotIdx) and (s.compare(pivotIdx, j) < 0):
  134. dec j
  135. if i < j:
  136. s.exchange(i, j)
  137. if pivotIdx == i:
  138. pivotIdx = j
  139. inc i
  140. elif pivotIdx == j:
  141. pivotIdx = i
  142. dec j
  143. else:
  144. inc i
  145. dec j
  146. else:
  147. break
  148. if (pivotIdx - l) < (r - pivotIdx):
  149. if (l + 1) < pivotIdx:
  150. s.quickSort(l, pivotIdx - 1)
  151. l = pivotIdx + 1
  152. else:
  153. if (pivotIdx + 1) < r:
  154. s.quickSort(pivotIdx + 1, r)
  155. if (l + 1) < pivotIdx:
  156. r = pivotIdx - 1
  157. else:
  158. break
  159. if l >= r:
  160. break
  161. proc sort*(s: var SuggestFileSymbolDatabase) =
  162. s.quickSort(s.lineInfo.low, s.lineInfo.high)
  163. s.isSorted = true
  164. proc add*(s: var SuggestFileSymbolDatabase; v: SymInfoPair) =
  165. doAssert(v.info.fileIndex == s.fileIndex)
  166. s.lineInfo.add(TinyLineInfo(
  167. line: v.info.line,
  168. col: v.info.col
  169. ))
  170. s.sym.add(v.sym)
  171. s.isDecl.add(v.isDecl)
  172. if s.trackCaughtExceptions:
  173. s.caughtExceptions.add(v.caughtExceptions)
  174. s.caughtExceptionsSet.add(v.caughtExceptionsSet)
  175. s.isSorted = false
  176. proc add*(s: var SuggestSymbolDatabase; v: SymInfoPair; trackCaughtExceptions: bool) =
  177. s.mgetOrPut(v.info.fileIndex, newSuggestFileSymbolDatabase(v.info.fileIndex, trackCaughtExceptions)).add(v)
  178. proc findSymInfoIndex*(s: var SuggestFileSymbolDatabase; li: TLineInfo): int =
  179. doAssert(li.fileIndex == s.fileIndex)
  180. if not s.isSorted:
  181. s.sort()
  182. var q = TinyLineInfo(
  183. line: li.line,
  184. col: li.col
  185. )
  186. result = binarySearch(s.lineInfo, q, cmp)