astalgo.nim 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Algorithms for the abstract syntax tree: hash tables, lists
  10. # and sets of nodes are supported. Efficiency is important as
  11. # the data structures here are used in various places of the compiler.
  12. import
  13. ast, astyaml, options, lineinfos, idents, rodutils,
  14. msgs
  15. import std/[hashes, intsets]
  16. import std/strutils except addf
  17. export astyaml.treeToYaml, astyaml.typeToYaml, astyaml.symToYaml, astyaml.lineInfoToStr
  18. when defined(nimPreviewSlimSystem):
  19. import std/assertions
  20. proc hashNode*(p: RootRef): Hash
  21. # these are for debugging only: They are not really deprecated, but I want
  22. # the warning so that release versions do not contain debugging statements:
  23. proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.}
  24. proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
  25. proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
  26. template debug*(x: PSym|PType|PNode) {.deprecated.} =
  27. when compiles(c.config):
  28. debug(c.config, x)
  29. elif compiles(c.graph.config):
  30. debug(c.graph.config, x)
  31. else:
  32. error()
  33. template debug*(x: auto) {.deprecated.} =
  34. echo x
  35. template mdbg*: bool {.deprecated.} =
  36. when compiles(c.graph):
  37. c.module.fileIdx == c.graph.config.projectMainIdx
  38. elif compiles(c.module):
  39. c.module.fileIdx == c.config.projectMainIdx
  40. elif compiles(c.c.module):
  41. c.c.module.fileIdx == c.c.config.projectMainIdx
  42. elif compiles(m.c.module):
  43. m.c.module.fileIdx == m.c.config.projectMainIdx
  44. elif compiles(cl.c.module):
  45. cl.c.module.fileIdx == cl.c.config.projectMainIdx
  46. elif compiles(p):
  47. when compiles(p.lex):
  48. p.lex.fileIdx == p.lex.config.projectMainIdx
  49. else:
  50. p.module.module.fileIdx == p.config.projectMainIdx
  51. elif compiles(m.module.fileIdx):
  52. m.module.fileIdx == m.config.projectMainIdx
  53. elif compiles(L.fileIdx):
  54. L.fileIdx == L.config.projectMainIdx
  55. else:
  56. error()
  57. # ---------------------------------------------------------------------------
  58. proc lookupInRecord*(n: PNode, field: PIdent): PSym
  59. proc mustRehash*(length, counter: int): bool
  60. proc nextTry*(h, maxHash: Hash): Hash {.inline.}
  61. # ------------- table[int, int] ---------------------------------------------
  62. const
  63. InvalidKey* = low(int)
  64. type
  65. TIIPair*{.final.} = object
  66. key*, val*: int
  67. TIIPairSeq* = seq[TIIPair]
  68. TIITable*{.final.} = object # table[int, int]
  69. counter*: int
  70. data*: TIIPairSeq
  71. proc initIITable*(x: var TIITable)
  72. proc iiTableGet*(t: TIITable, key: int): int
  73. proc iiTablePut*(t: var TIITable, key, val: int)
  74. # implementation
  75. proc skipConvCastAndClosure*(n: PNode): PNode =
  76. result = n
  77. while true:
  78. case result.kind
  79. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
  80. nkClosure:
  81. result = result[0]
  82. of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
  83. result = result[1]
  84. else: break
  85. proc sameValue*(a, b: PNode): bool =
  86. result = false
  87. case a.kind
  88. of nkCharLit..nkUInt64Lit:
  89. if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) == getInt(b)
  90. of nkFloatLit..nkFloat64Lit:
  91. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
  92. of nkStrLit..nkTripleStrLit:
  93. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
  94. else:
  95. # don't raise an internal error for 'nim check':
  96. #InternalError(a.info, "SameValue")
  97. discard
  98. proc leValue*(a, b: PNode): bool =
  99. # a <= b?
  100. result = false
  101. case a.kind
  102. of nkCharLit..nkUInt64Lit:
  103. if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) <= getInt(b)
  104. of nkFloatLit..nkFloat64Lit:
  105. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
  106. of nkStrLit..nkTripleStrLit:
  107. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
  108. else:
  109. # don't raise an internal error for 'nim check':
  110. #InternalError(a.info, "leValue")
  111. discard
  112. proc weakLeValue*(a, b: PNode): TImplication =
  113. if a.kind notin nkLiterals or b.kind notin nkLiterals:
  114. result = impUnknown
  115. else:
  116. result = if leValue(a, b): impYes else: impNo
  117. proc lookupInRecord(n: PNode, field: PIdent): PSym =
  118. result = nil
  119. case n.kind
  120. of nkRecList:
  121. for i in 0..<n.len:
  122. result = lookupInRecord(n[i], field)
  123. if result != nil: return
  124. of nkRecCase:
  125. if (n[0].kind != nkSym): return nil
  126. result = lookupInRecord(n[0], field)
  127. if result != nil: return
  128. for i in 1..<n.len:
  129. case n[i].kind
  130. of nkOfBranch, nkElse:
  131. result = lookupInRecord(lastSon(n[i]), field)
  132. if result != nil: return
  133. else: return nil
  134. of nkSym:
  135. if n.sym.name.id == field.id: result = n.sym
  136. else: return nil
  137. proc getModule*(s: PSym): PSym =
  138. result = s
  139. assert((result.kind == skModule) or (result.owner != result))
  140. while result != nil and result.kind != skModule: result = result.owner
  141. proc fromSystem*(op: PSym): bool {.inline.} = sfSystemModule in getModule(op).flags
  142. proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
  143. for i in start..<list.len:
  144. if list[i].kind == nkSym:
  145. result = list[i].sym
  146. if result.name.id == ident.id: return
  147. else: return nil
  148. result = nil
  149. proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
  150. result = false
  151. if a[0] != b[0]: return false
  152. var alen = a.len - 1
  153. while alen > 0 and a[alen] != '`': dec(alen)
  154. if alen <= 0: alen = a.len
  155. var i = 1
  156. var j = 1
  157. while true:
  158. while i < alen and a[i] == '_': inc i
  159. while j < b.len and b[j] == '_': inc j
  160. var aa = if i < alen: toLowerAscii(a[i]) else: '\0'
  161. var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
  162. if aa != bb: return false
  163. # the characters are identical:
  164. if i >= alen:
  165. # both cursors at the end:
  166. if j >= b.len: return true
  167. # not yet at the end of 'b':
  168. return false
  169. elif j >= b.len:
  170. return false
  171. inc i
  172. inc j
  173. proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
  174. ## Named parameters are special because a named parameter can be
  175. ## gensym'ed and then they have '\`<number>' suffix that we need to
  176. ## ignore, see compiler / evaltempl.nim, snippet:
  177. ## ```nim
  178. ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
  179. ## if c.instLines: actual.info else: templ.info)
  180. ## ```
  181. result = nil
  182. for i in 1..<list.len:
  183. let it = list[i].sym
  184. if it.name.id == ident.id or
  185. sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
  186. proc hashNode(p: RootRef): Hash =
  187. result = hash(cast[pointer](p))
  188. proc mustRehash(length, counter: int): bool =
  189. assert(length > counter)
  190. result = (length * 2 < counter * 3) or (length - counter < 4)
  191. import std/tables
  192. const backrefStyle = "\e[90m"
  193. const enumStyle = "\e[34m"
  194. const numberStyle = "\e[33m"
  195. const stringStyle = "\e[32m"
  196. const resetStyle = "\e[0m"
  197. type
  198. DebugPrinter = object
  199. conf: ConfigRef
  200. visited: Table[pointer, int]
  201. renderSymType: bool
  202. indent: int
  203. currentLine: int
  204. firstItem: bool
  205. useColor: bool
  206. res: string
  207. proc indentMore(this: var DebugPrinter) =
  208. this.indent += 2
  209. proc indentLess(this: var DebugPrinter) =
  210. this.indent -= 2
  211. proc newlineAndIndent(this: var DebugPrinter) =
  212. this.res.add "\n"
  213. this.currentLine += 1
  214. for i in 0..<this.indent:
  215. this.res.add ' '
  216. proc openCurly(this: var DebugPrinter) =
  217. this.res.add "{"
  218. this.indentMore
  219. this.firstItem = true
  220. proc closeCurly(this: var DebugPrinter) =
  221. this.indentLess
  222. this.newlineAndIndent
  223. this.res.add "}"
  224. proc comma(this: var DebugPrinter) =
  225. this.res.add ", "
  226. proc openBracket(this: var DebugPrinter) =
  227. this.res.add "["
  228. #this.indentMore
  229. proc closeBracket(this: var DebugPrinter) =
  230. #this.indentLess
  231. this.res.add "]"
  232. proc key(this: var DebugPrinter; key: string) =
  233. if not this.firstItem:
  234. this.res.add ","
  235. this.firstItem = false
  236. this.newlineAndIndent
  237. this.res.add "\""
  238. this.res.add key
  239. this.res.add "\": "
  240. proc value(this: var DebugPrinter; value: string) =
  241. if this.useColor:
  242. this.res.add stringStyle
  243. this.res.add "\""
  244. this.res.add value
  245. this.res.add "\""
  246. if this.useColor:
  247. this.res.add resetStyle
  248. proc value(this: var DebugPrinter; value: BiggestInt) =
  249. if this.useColor:
  250. this.res.add numberStyle
  251. this.res.addInt value
  252. if this.useColor:
  253. this.res.add resetStyle
  254. proc value[T: enum](this: var DebugPrinter; value: T) =
  255. if this.useColor:
  256. this.res.add enumStyle
  257. this.res.add "\""
  258. this.res.add $value
  259. this.res.add "\""
  260. if this.useColor:
  261. this.res.add resetStyle
  262. proc value[T: enum](this: var DebugPrinter; value: set[T]) =
  263. this.openBracket
  264. let high = card(value)-1
  265. var i = 0
  266. for v in value:
  267. this.value v
  268. if i != high:
  269. this.comma
  270. inc i
  271. this.closeBracket
  272. template earlyExit(this: var DebugPrinter; n: PType | PNode | PSym) =
  273. if n == nil:
  274. this.res.add "null"
  275. return
  276. let index = this.visited.getOrDefault(cast[pointer](n), -1)
  277. if index < 0:
  278. this.visited[cast[pointer](n)] = this.currentLine
  279. else:
  280. if this.useColor:
  281. this.res.add backrefStyle
  282. this.res.add "<defined "
  283. this.res.addInt(this.currentLine - index)
  284. this.res.add " lines upwards>"
  285. if this.useColor:
  286. this.res.add resetStyle
  287. return
  288. proc value(this: var DebugPrinter; value: PType)
  289. proc value(this: var DebugPrinter; value: PNode)
  290. proc value(this: var DebugPrinter; value: PSym) =
  291. earlyExit(this, value)
  292. this.openCurly
  293. this.key("kind")
  294. this.value(value.kind)
  295. this.key("name")
  296. this.value(value.name.s)
  297. this.key("id")
  298. this.value(value.id)
  299. if value.kind in {skField, skEnumField, skParam}:
  300. this.key("position")
  301. this.value(value.position)
  302. if card(value.flags) > 0:
  303. this.key("flags")
  304. this.value(value.flags)
  305. if this.renderSymType and value.typ != nil:
  306. this.key "typ"
  307. this.value(value.typ)
  308. this.closeCurly
  309. proc value(this: var DebugPrinter; value: PType) =
  310. earlyExit(this, value)
  311. this.openCurly
  312. this.key "kind"
  313. this.value value.kind
  314. this.key "id"
  315. this.value value.id
  316. if value.sym != nil:
  317. this.key "sym"
  318. this.value value.sym
  319. #this.value value.sym.name.s
  320. if card(value.flags) > 0:
  321. this.key "flags"
  322. this.value value.flags
  323. if value.kind in IntegralTypes and value.n != nil:
  324. this.key "n"
  325. this.value value.n
  326. this.key "sons"
  327. this.openBracket
  328. for i, a in value.ikids:
  329. if i > 0: this.comma
  330. this.value a
  331. this.closeBracket
  332. if value.n != nil:
  333. this.key "n"
  334. this.value value.n
  335. this.closeCurly
  336. proc value(this: var DebugPrinter; value: PNode) =
  337. earlyExit(this, value)
  338. this.openCurly
  339. this.key "kind"
  340. this.value value.kind
  341. if value.comment.len > 0:
  342. this.key "comment"
  343. this.value value.comment
  344. when defined(useNodeIds):
  345. this.key "id"
  346. this.value value.id
  347. if this.conf != nil:
  348. this.key "info"
  349. this.value $lineInfoToStr(this.conf, value.info)
  350. if value.flags != {}:
  351. this.key "flags"
  352. this.value value.flags
  353. if value.typ != nil:
  354. this.key "typ"
  355. this.value value.typ.kind
  356. else:
  357. this.key "typ"
  358. this.value "nil"
  359. case value.kind
  360. of nkCharLit..nkUInt64Lit:
  361. this.key "intVal"
  362. this.value value.intVal
  363. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  364. this.key "floatVal"
  365. this.value value.floatVal.toStrMaxPrecision
  366. of nkStrLit..nkTripleStrLit:
  367. this.key "strVal"
  368. this.value value.strVal
  369. of nkSym:
  370. this.key "sym"
  371. this.value value.sym
  372. #this.value value.sym.name.s
  373. of nkIdent:
  374. if value.ident != nil:
  375. this.key "ident"
  376. this.value value.ident.s
  377. else:
  378. if this.renderSymType and value.typ != nil:
  379. this.key "typ"
  380. this.value value.typ
  381. if value.len > 0:
  382. this.key "sons"
  383. this.openBracket
  384. for i in 0..<value.len:
  385. this.value value[i]
  386. if i != value.len - 1:
  387. this.comma
  388. this.closeBracket
  389. this.closeCurly
  390. proc debug(n: PSym; conf: ConfigRef) =
  391. var this = DebugPrinter(
  392. visited: initTable[pointer, int](),
  393. renderSymType: true,
  394. useColor: not defined(windows)
  395. )
  396. this.value(n)
  397. echo($this.res)
  398. proc debug(n: PType; conf: ConfigRef) =
  399. var this = DebugPrinter(
  400. visited: initTable[pointer, int](),
  401. renderSymType: true,
  402. useColor: not defined(windows)
  403. )
  404. this.value(n)
  405. echo($this.res)
  406. proc debug(n: PNode; conf: ConfigRef) =
  407. var this = DebugPrinter(
  408. visited: initTable[pointer, int](),
  409. renderSymType: false,
  410. useColor: not defined(windows)
  411. )
  412. this.value(n)
  413. echo($this.res)
  414. proc nextTry(h, maxHash: Hash): Hash {.inline.} =
  415. result = ((5 * h) + 1) and maxHash
  416. # For any initial h in range(maxHash), repeating that maxHash times
  417. # generates each int in range(maxHash) exactly once (see any text on
  418. # random-number generation for proof).
  419. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
  420. # returns true whether n is in t
  421. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  422. while t.data[h] != nil:
  423. if t.data[h] == obj:
  424. return true
  425. h = nextTry(h, high(t.data))
  426. result = false
  427. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  428. var h: Hash = hashNode(obj) and high(data)
  429. while data[h] != nil:
  430. assert(data[h] != obj)
  431. h = nextTry(h, high(data))
  432. assert(data[h] == nil)
  433. data[h] = obj
  434. proc objectSetEnlarge(t: var TObjectSet) =
  435. var n: TObjectSeq
  436. newSeq(n, t.data.len * GrowthFactor)
  437. for i in 0..high(t.data):
  438. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  439. swap(t.data, n)
  440. proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
  441. if mustRehash(t.data.len, t.counter): objectSetEnlarge(t)
  442. objectSetRawInsert(t.data, obj)
  443. inc(t.counter)
  444. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
  445. # returns true if obj is already in the string table:
  446. var h: Hash = hashNode(obj) and high(t.data)
  447. while true:
  448. var it = t.data[h]
  449. if it == nil: break
  450. if it == obj:
  451. return true # found it
  452. h = nextTry(h, high(t.data))
  453. if mustRehash(t.data.len, t.counter):
  454. objectSetEnlarge(t)
  455. objectSetRawInsert(t.data, obj)
  456. else:
  457. assert(t.data[h] == nil)
  458. t.data[h] = obj
  459. inc(t.counter)
  460. result = false
  461. proc strTableContains*(t: TStrTable, n: PSym): bool =
  462. var h: Hash = n.name.h and high(t.data) # start with real hash value
  463. while t.data[h] != nil:
  464. if (t.data[h] == n):
  465. return true
  466. h = nextTry(h, high(t.data))
  467. result = false
  468. proc strTableRawInsert(data: var seq[PSym], n: PSym) =
  469. var h: Hash = n.name.h and high(data)
  470. while data[h] != nil:
  471. if data[h] == n:
  472. # allowed for 'export' feature:
  473. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  474. return
  475. h = nextTry(h, high(data))
  476. assert(data[h] == nil)
  477. data[h] = n
  478. proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
  479. assert prevSym.name.h == newSym.name.h
  480. var h: Hash = prevSym.name.h and high(data)
  481. while data[h] != nil:
  482. if data[h] == prevSym:
  483. data[h] = newSym
  484. return
  485. h = nextTry(h, high(data))
  486. assert false
  487. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  488. symTabReplaceRaw(t.data, prevSym, newSym)
  489. proc strTableEnlarge(t: var TStrTable) =
  490. var n: seq[PSym]
  491. newSeq(n, t.data.len * GrowthFactor)
  492. for i in 0..high(t.data):
  493. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  494. swap(t.data, n)
  495. proc strTableAdd*(t: var TStrTable, n: PSym) =
  496. if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
  497. strTableRawInsert(t.data, n)
  498. inc(t.counter)
  499. proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
  500. onConflictKeepOld = false): PSym =
  501. # if `t` has a conflicting symbol (same identifier as `n`), return it
  502. # otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true`
  503. # and a conflict was found.
  504. assert n.name != nil
  505. var h: Hash = n.name.h and high(t.data)
  506. var replaceSlot = -1
  507. while true:
  508. var it = t.data[h]
  509. if it == nil: break
  510. # Semantic checking can happen multiple times thanks to templates
  511. # and overloading: (var x=@[]; x).mapIt(it).
  512. # So it is possible the very same sym is added multiple
  513. # times to the symbol table which we allow here with the 'it == n' check.
  514. if it.name.id == n.name.id:
  515. if it == n: return nil
  516. replaceSlot = h
  517. h = nextTry(h, high(t.data))
  518. if replaceSlot >= 0:
  519. result = t.data[replaceSlot] # found it
  520. if not onConflictKeepOld:
  521. t.data[replaceSlot] = n # overwrite it with newer definition!
  522. return result # but return the old one
  523. elif mustRehash(t.data.len, t.counter):
  524. strTableEnlarge(t)
  525. strTableRawInsert(t.data, n)
  526. else:
  527. assert(t.data[h] == nil)
  528. t.data[h] = n
  529. inc(t.counter)
  530. result = nil
  531. proc strTableIncl*(t: var TStrTable, n: PSym;
  532. onConflictKeepOld = false): bool {.discardable.} =
  533. result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
  534. proc strTableGet*(t: TStrTable, name: PIdent): PSym =
  535. var h: Hash = name.h and high(t.data)
  536. while true:
  537. result = t.data[h]
  538. if result == nil: break
  539. if result.name.id == name.id: break
  540. h = nextTry(h, high(t.data))
  541. type
  542. TIdentIter* = object # iterator over all syms with same identifier
  543. h*: Hash # current hash
  544. name*: PIdent
  545. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
  546. # hot spots
  547. var h = ti.h and high(tab.data)
  548. var start = h
  549. var p {.cursor.} = tab.data[h]
  550. while p != nil:
  551. if p.name.id == ti.name.id: break
  552. h = nextTry(h, high(tab.data))
  553. if h == start:
  554. p = nil
  555. break
  556. p = tab.data[h]
  557. if p != nil:
  558. result = p # increase the count
  559. else:
  560. result = nil
  561. ti.h = nextTry(h, high(tab.data))
  562. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  563. ti.h = s.h
  564. ti.name = s
  565. if tab.counter == 0: result = nil
  566. else: result = nextIdentIter(ti, tab)
  567. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  568. excluding: IntSet): PSym =
  569. var h: Hash = ti.h and high(tab.data)
  570. var start = h
  571. result = tab.data[h]
  572. while result != nil:
  573. if result.name.id == ti.name.id and not contains(excluding, result.id):
  574. break
  575. h = nextTry(h, high(tab.data))
  576. if h == start:
  577. result = nil
  578. break
  579. result = tab.data[h]
  580. ti.h = nextTry(h, high(tab.data))
  581. if result != nil and contains(excluding, result.id): result = nil
  582. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  583. excluding: IntSet): PSym =
  584. ti.h = s.h
  585. ti.name = s
  586. if tab.counter == 0: result = nil
  587. else: result = nextIdentExcluding(ti, tab, excluding)
  588. type
  589. TTabIter* = object
  590. h: Hash
  591. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
  592. # usage:
  593. # var
  594. # i: TTabIter
  595. # s: PSym
  596. # s = InitTabIter(i, table)
  597. # while s != nil:
  598. # ...
  599. # s = NextIter(i, table)
  600. #
  601. result = nil
  602. while (ti.h <= high(tab.data)):
  603. result = tab.data[ti.h]
  604. inc(ti.h) # ... and increment by one always
  605. if result != nil: break
  606. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
  607. ti.h = 0
  608. if tab.counter == 0:
  609. result = nil
  610. else:
  611. result = nextIter(ti, tab)
  612. iterator items*(tab: TStrTable): PSym =
  613. var it: TTabIter = default(TTabIter)
  614. var s = initTabIter(it, tab)
  615. while s != nil:
  616. yield s
  617. s = nextIter(it, tab)
  618. proc initIITable(x: var TIITable) =
  619. x.counter = 0
  620. newSeq(x.data, StartSize)
  621. for i in 0..<StartSize: x.data[i].key = InvalidKey
  622. proc iiTableRawGet(t: TIITable, key: int): int =
  623. var h: Hash
  624. h = key and high(t.data) # start with real hash value
  625. while t.data[h].key != InvalidKey:
  626. if t.data[h].key == key: return h
  627. h = nextTry(h, high(t.data))
  628. result = -1
  629. proc iiTableGet(t: TIITable, key: int): int =
  630. var index = iiTableRawGet(t, key)
  631. if index >= 0: result = t.data[index].val
  632. else: result = InvalidKey
  633. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  634. var h: Hash
  635. h = key and high(data)
  636. while data[h].key != InvalidKey:
  637. assert(data[h].key != key)
  638. h = nextTry(h, high(data))
  639. assert(data[h].key == InvalidKey)
  640. data[h].key = key
  641. data[h].val = val
  642. proc iiTablePut(t: var TIITable, key, val: int) =
  643. var index = iiTableRawGet(t, key)
  644. if index >= 0:
  645. assert(t.data[index].key != InvalidKey)
  646. t.data[index].val = val
  647. else:
  648. if mustRehash(t.data.len, t.counter):
  649. var n: TIIPairSeq
  650. newSeq(n, t.data.len * GrowthFactor)
  651. for i in 0..high(n): n[i].key = InvalidKey
  652. for i in 0..high(t.data):
  653. if t.data[i].key != InvalidKey:
  654. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  655. swap(t.data, n)
  656. iiTableRawInsert(t.data, key, val)
  657. inc(t.counter)
  658. proc listSymbolNames*(symbols: openArray[PSym]): string =
  659. result = ""
  660. for sym in symbols:
  661. if result.len > 0:
  662. result.add ", "
  663. result.add sym.name.s
  664. proc isDiscriminantField*(n: PNode): bool =
  665. if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags
  666. elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags
  667. else: false