astalgo.nim 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  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, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
  14. proc hashNode*(p: RootRef): Hash
  15. proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
  16. # Convert a tree into its YAML representation; this is used by the
  17. # YAML code generator and it is invaluable for debugging purposes.
  18. # If maxRecDepht <> -1 then it won't print the whole graph.
  19. proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
  20. proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
  21. proc lineInfoToStr*(info: TLineInfo): Rope
  22. # ----------------------- node sets: ---------------------------------------
  23. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
  24. # returns true whether n is in t
  25. proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
  26. # include an element n in the table t
  27. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
  28. # more are not needed ...
  29. # ----------------------- str table -----------------------------------------
  30. proc strTableContains*(t: TStrTable, n: PSym): bool
  31. proc strTableAdd*(t: var TStrTable, n: PSym)
  32. proc strTableGet*(t: TStrTable, name: PIdent): PSym
  33. type
  34. TTabIter*{.final.} = object # consider all fields here private
  35. h*: Hash # current hash
  36. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
  37. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
  38. # usage:
  39. # var
  40. # i: TTabIter
  41. # s: PSym
  42. # s = InitTabIter(i, table)
  43. # while s != nil:
  44. # ...
  45. # s = NextIter(i, table)
  46. #
  47. type
  48. TIdentIter*{.final.} = object # iterator over all syms with same identifier
  49. h*: Hash # current hash
  50. name*: PIdent
  51. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
  52. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
  53. # these are for debugging only: They are not really deprecated, but I want
  54. # the warning so that release versions do not contain debugging statements:
  55. proc debug*(n: PSym) {.deprecated.}
  56. proc debug*(n: PType) {.deprecated.}
  57. proc debug*(n: PNode) {.deprecated.}
  58. template mdbg*: bool {.dirty.} =
  59. when compiles(c.module):
  60. c.module.fileIdx == gProjectMainIdx
  61. elif compiles(c.c.module):
  62. c.c.module.fileIdx == gProjectMainIdx
  63. elif compiles(m.c.module):
  64. m.c.module.fileIdx == gProjectMainIdx
  65. elif compiles(cl.c.module):
  66. cl.c.module.fileIdx == gProjectMainIdx
  67. elif compiles(p):
  68. when compiles(p.lex):
  69. p.lex.fileIdx == gProjectMainIdx
  70. else:
  71. p.module.module.fileIdx == gProjectMainIdx
  72. elif compiles(m.module.fileIdx):
  73. m.module.fileIdx == gProjectMainIdx
  74. elif compiles(L.fileIdx):
  75. L.fileIdx == gProjectMainIdx
  76. else:
  77. error()
  78. # --------------------------- ident tables ----------------------------------
  79. proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
  80. proc idTableGet*(t: TIdTable, key: int): RootRef
  81. proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
  82. proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
  83. # checks if `t` contains the `key` (compared by the pointer value, not only
  84. # `key`'s id)
  85. proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
  86. proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
  87. # ---------------------------------------------------------------------------
  88. proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
  89. proc lookupInRecord*(n: PNode, field: PIdent): PSym
  90. proc getModule*(s: PSym): PSym
  91. proc mustRehash*(length, counter: int): bool
  92. proc nextTry*(h, maxHash: Hash): Hash {.inline.}
  93. # ------------- table[int, int] ---------------------------------------------
  94. const
  95. InvalidKey* = low(int)
  96. type
  97. TIIPair*{.final.} = object
  98. key*, val*: int
  99. TIIPairSeq* = seq[TIIPair]
  100. TIITable*{.final.} = object # table[int, int]
  101. counter*: int
  102. data*: TIIPairSeq
  103. proc initIiTable*(x: var TIITable)
  104. proc iiTableGet*(t: TIITable, key: int): int
  105. proc iiTablePut*(t: var TIITable, key, val: int)
  106. # implementation
  107. proc skipConvAndClosure*(n: PNode): PNode =
  108. result = n
  109. while true:
  110. case result.kind
  111. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
  112. nkClosure:
  113. result = result.sons[0]
  114. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  115. result = result.sons[1]
  116. else: break
  117. proc sameValue*(a, b: PNode): bool =
  118. result = false
  119. case a.kind
  120. of nkCharLit..nkUInt64Lit:
  121. if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
  122. of nkFloatLit..nkFloat64Lit:
  123. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
  124. of nkStrLit..nkTripleStrLit:
  125. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
  126. else:
  127. # don't raise an internal error for 'nim check':
  128. #InternalError(a.info, "SameValue")
  129. discard
  130. proc leValue*(a, b: PNode): bool =
  131. # a <= b?
  132. result = false
  133. case a.kind
  134. of nkCharLit..nkUInt32Lit:
  135. if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
  136. of nkFloatLit..nkFloat64Lit:
  137. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
  138. of nkStrLit..nkTripleStrLit:
  139. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
  140. else:
  141. # don't raise an internal error for 'nim check':
  142. #InternalError(a.info, "leValue")
  143. discard
  144. proc weakLeValue*(a, b: PNode): TImplication =
  145. if a.kind notin nkLiterals or b.kind notin nkLiterals:
  146. result = impUnknown
  147. else:
  148. result = if leValue(a, b): impYes else: impNo
  149. proc lookupInRecord(n: PNode, field: PIdent): PSym =
  150. result = nil
  151. case n.kind
  152. of nkRecList:
  153. for i in countup(0, sonsLen(n) - 1):
  154. result = lookupInRecord(n.sons[i], field)
  155. if result != nil: return
  156. of nkRecCase:
  157. if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
  158. result = lookupInRecord(n.sons[0], field)
  159. if result != nil: return
  160. for i in countup(1, sonsLen(n) - 1):
  161. case n.sons[i].kind
  162. of nkOfBranch, nkElse:
  163. result = lookupInRecord(lastSon(n.sons[i]), field)
  164. if result != nil: return
  165. else: internalError(n.info, "lookupInRecord(record case branch)")
  166. of nkSym:
  167. if n.sym.name.id == field.id: result = n.sym
  168. else: internalError(n.info, "lookupInRecord()")
  169. proc getModule(s: PSym): PSym =
  170. result = s
  171. assert((result.kind == skModule) or (result.owner != result))
  172. while result != nil and result.kind != skModule: result = result.owner
  173. proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
  174. for i in countup(start, sonsLen(list) - 1):
  175. if list.sons[i].kind == nkSym:
  176. result = list.sons[i].sym
  177. if result.name.id == ident.id: return
  178. else: internalError(list.info, "getSymFromList")
  179. result = nil
  180. proc hashNode(p: RootRef): Hash =
  181. result = hash(cast[pointer](p))
  182. proc mustRehash(length, counter: int): bool =
  183. assert(length > counter)
  184. result = (length * 2 < counter * 3) or (length - counter < 4)
  185. proc rspaces(x: int): Rope =
  186. # returns x spaces
  187. result = rope(spaces(x))
  188. proc toYamlChar(c: char): string =
  189. case c
  190. of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
  191. of '\'', '\"', '\\': result = '\\' & c
  192. else: result = $c
  193. proc makeYamlString*(s: string): Rope =
  194. # We have to split long strings into many ropes. Otherwise
  195. # this could trigger InternalError(111). See the ropes module for
  196. # further information.
  197. const MaxLineLength = 64
  198. result = nil
  199. var res = "\""
  200. for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
  201. if (i + 1) mod MaxLineLength == 0:
  202. add(res, '\"')
  203. add(res, "\n")
  204. add(result, rope(res))
  205. res = "\"" # reset
  206. add(res, toYamlChar(s[i]))
  207. add(res, '\"')
  208. add(result, rope(res))
  209. proc flagsToStr[T](flags: set[T]): Rope =
  210. if flags == {}:
  211. result = rope("[]")
  212. else:
  213. result = nil
  214. for x in items(flags):
  215. if result != nil: add(result, ", ")
  216. add(result, makeYamlString($x))
  217. result = "[" & result & "]"
  218. proc lineInfoToStr(info: TLineInfo): Rope =
  219. result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
  220. rope(toLinenumber(info)),
  221. rope(toColumn(info))]
  222. proc treeToYamlAux(n: PNode, marker: var IntSet,
  223. indent, maxRecDepth: int): Rope
  224. proc symToYamlAux(n: PSym, marker: var IntSet,
  225. indent, maxRecDepth: int): Rope
  226. proc typeToYamlAux(n: PType, marker: var IntSet,
  227. indent, maxRecDepth: int): Rope
  228. proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
  229. # array of (name, value) pairs
  230. var istr = rspaces(indent + 2)
  231. result = rope("{")
  232. var i = 0
  233. while i <= high(c):
  234. if i > 0: add(result, ",")
  235. addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
  236. inc(i, 2)
  237. addf(result, "$N$1}", [rspaces(indent)])
  238. proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
  239. maxRecDepth: int): Rope =
  240. if n == nil:
  241. result = rope("null")
  242. elif containsOrIncl(marker, n.id):
  243. result = "\"$1 @$2\"" % [rope(n.name.s), rope(
  244. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  245. else:
  246. var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
  247. result = ropeConstr(indent, [rope("kind"),
  248. makeYamlString($n.kind),
  249. rope("name"), makeYamlString(n.name.s),
  250. rope("typ"), typeToYamlAux(n.typ, marker,
  251. indent + 2, maxRecDepth - 1),
  252. rope("info"), lineInfoToStr(n.info),
  253. rope("flags"), flagsToStr(n.flags),
  254. rope("magic"), makeYamlString($n.magic),
  255. rope("ast"), ast, rope("options"),
  256. flagsToStr(n.options), rope("position"),
  257. rope(n.position)])
  258. proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
  259. maxRecDepth: int): Rope =
  260. if n == nil:
  261. result = rope("null")
  262. elif containsOrIncl(marker, n.id):
  263. result = "\"$1 @$2\"" % [rope($n.kind), rope(
  264. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  265. else:
  266. if sonsLen(n) > 0:
  267. result = rope("[")
  268. for i in countup(0, sonsLen(n) - 1):
  269. if i > 0: add(result, ",")
  270. addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
  271. marker, indent + 4, maxRecDepth - 1)])
  272. addf(result, "$N$1]", [rspaces(indent + 2)])
  273. else:
  274. result = rope("null")
  275. result = ropeConstr(indent, [rope("kind"),
  276. makeYamlString($n.kind),
  277. rope("sym"), symToYamlAux(n.sym, marker,
  278. indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
  279. indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
  280. rope("callconv"),
  281. makeYamlString(CallingConvToStr[n.callConv]),
  282. rope("size"), rope(n.size),
  283. rope("align"), rope(n.align),
  284. rope("sons"), result])
  285. proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
  286. maxRecDepth: int): Rope =
  287. if n == nil:
  288. result = rope("null")
  289. else:
  290. var istr = rspaces(indent + 2)
  291. result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
  292. if maxRecDepth != 0:
  293. addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
  294. case n.kind
  295. of nkCharLit..nkInt64Lit:
  296. addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  297. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  298. addf(result, ",$N$1\"floatVal\": $2",
  299. [istr, rope(n.floatVal.toStrMaxPrecision)])
  300. of nkStrLit..nkTripleStrLit:
  301. if n.strVal.isNil:
  302. addf(result, ",$N$1\"strVal\": null", [istr])
  303. else:
  304. addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  305. of nkSym:
  306. addf(result, ",$N$1\"sym\": $2",
  307. [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
  308. of nkIdent:
  309. if n.ident != nil:
  310. addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  311. else:
  312. addf(result, ",$N$1\"ident\": null", [istr])
  313. else:
  314. if sonsLen(n) > 0:
  315. addf(result, ",$N$1\"sons\": [", [istr])
  316. for i in countup(0, sonsLen(n) - 1):
  317. if i > 0: add(result, ",")
  318. addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
  319. marker, indent + 4, maxRecDepth - 1)])
  320. addf(result, "$N$1]", [istr])
  321. addf(result, ",$N$1\"typ\": $2",
  322. [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
  323. addf(result, "$N$1}", [rspaces(indent)])
  324. proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
  325. var marker = initIntSet()
  326. result = treeToYamlAux(n, marker, indent, maxRecDepth)
  327. proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
  328. var marker = initIntSet()
  329. result = typeToYamlAux(n, marker, indent, maxRecDepth)
  330. proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
  331. var marker = initIntSet()
  332. result = symToYamlAux(n, marker, indent, maxRecDepth)
  333. proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
  334. proc debugType(n: PType, maxRecDepth=100): Rope =
  335. if n == nil:
  336. result = rope("null")
  337. else:
  338. result = rope($n.kind)
  339. if n.sym != nil:
  340. add(result, " ")
  341. add(result, n.sym.name.s)
  342. if n.kind in IntegralTypes and n.n != nil:
  343. add(result, ", node: ")
  344. add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
  345. if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
  346. add(result, "(")
  347. for i in countup(0, sonsLen(n) - 1):
  348. if i > 0: add(result, ", ")
  349. if n.sons[i] == nil:
  350. add(result, "null")
  351. else:
  352. add(result, debugType(n.sons[i], maxRecDepth-1))
  353. if n.kind == tyObject and n.n != nil:
  354. add(result, ", node: ")
  355. add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
  356. add(result, ")")
  357. proc debugTree(n: PNode, indent: int, maxRecDepth: int;
  358. renderType=false): Rope =
  359. if n == nil:
  360. result = rope("null")
  361. else:
  362. var istr = rspaces(indent + 2)
  363. result = "{$N$1\"kind\": $2" %
  364. [istr, makeYamlString($n.kind)]
  365. when defined(useNodeIds):
  366. addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)])
  367. addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
  368. if maxRecDepth != 0:
  369. addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
  370. case n.kind
  371. of nkCharLit..nkUInt64Lit:
  372. addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  373. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  374. addf(result, ",$N$1\"floatVal\": $2",
  375. [istr, rope(n.floatVal.toStrMaxPrecision)])
  376. of nkStrLit..nkTripleStrLit:
  377. if n.strVal.isNil:
  378. addf(result, ",$N$1\"strVal\": null", [istr])
  379. else:
  380. addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  381. of nkSym:
  382. addf(result, ",$N$1\"sym\": $2_$3",
  383. [istr, rope(n.sym.name.s), rope(n.sym.id)])
  384. # [istr, symToYaml(n.sym, indent, maxRecDepth),
  385. # rope(n.sym.id)])
  386. if renderType and n.sym.typ != nil:
  387. addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
  388. of nkIdent:
  389. if n.ident != nil:
  390. addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  391. else:
  392. addf(result, ",$N$1\"ident\": null", [istr])
  393. else:
  394. if sonsLen(n) > 0:
  395. addf(result, ",$N$1\"sons\": [", [istr])
  396. for i in countup(0, sonsLen(n) - 1):
  397. if i > 0: add(result, ",")
  398. addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
  399. indent + 4, maxRecDepth - 1, renderType)])
  400. addf(result, "$N$1]", [istr])
  401. addf(result, "$N$1}", [rspaces(indent)])
  402. proc debug(n: PSym) =
  403. if n == nil:
  404. echo("null")
  405. elif n.kind == skUnknown:
  406. echo("skUnknown")
  407. else:
  408. #writeLine(stdout, $symToYaml(n, 0, 1))
  409. echo("$1_$2: $3, $4, $5, $6" % [
  410. n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
  411. $lineInfoToStr(n.info), $n.kind])
  412. proc debug(n: PType) =
  413. echo($debugType(n))
  414. proc debug(n: PNode) =
  415. echo($debugTree(n, 0, 100))
  416. proc nextTry(h, maxHash: Hash): Hash =
  417. result = ((5 * h) + 1) and maxHash
  418. # For any initial h in range(maxHash), repeating that maxHash times
  419. # generates each int in range(maxHash) exactly once (see any text on
  420. # random-number generation for proof).
  421. proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
  422. # returns true whether n is in t
  423. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  424. while t.data[h] != nil:
  425. if t.data[h] == obj:
  426. return true
  427. h = nextTry(h, high(t.data))
  428. result = false
  429. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  430. var h: Hash = hashNode(obj) and high(data)
  431. while data[h] != nil:
  432. assert(data[h] != obj)
  433. h = nextTry(h, high(data))
  434. assert(data[h] == nil)
  435. data[h] = obj
  436. proc objectSetEnlarge(t: var TObjectSet) =
  437. var n: TObjectSeq
  438. newSeq(n, len(t.data) * GrowthFactor)
  439. for i in countup(0, high(t.data)):
  440. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  441. swap(t.data, n)
  442. proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
  443. if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
  444. objectSetRawInsert(t.data, obj)
  445. inc(t.counter)
  446. proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
  447. # returns true if obj is already in the string table:
  448. var h: Hash = hashNode(obj) and high(t.data)
  449. while true:
  450. var it = t.data[h]
  451. if it == nil: break
  452. if it == obj:
  453. return true # found it
  454. h = nextTry(h, high(t.data))
  455. if mustRehash(len(t.data), t.counter):
  456. objectSetEnlarge(t)
  457. objectSetRawInsert(t.data, obj)
  458. else:
  459. assert(t.data[h] == nil)
  460. t.data[h] = obj
  461. inc(t.counter)
  462. result = false
  463. proc strTableContains(t: TStrTable, n: PSym): bool =
  464. var h: Hash = n.name.h and high(t.data) # start with real hash value
  465. while t.data[h] != nil:
  466. if (t.data[h] == n):
  467. return true
  468. h = nextTry(h, high(t.data))
  469. result = false
  470. proc strTableRawInsert(data: var TSymSeq, n: PSym) =
  471. var h: Hash = n.name.h and high(data)
  472. if sfImmediate notin n.flags:
  473. # fast path:
  474. while data[h] != nil:
  475. if data[h] == n:
  476. # allowed for 'export' feature:
  477. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  478. return
  479. h = nextTry(h, high(data))
  480. assert(data[h] == nil)
  481. data[h] = n
  482. else:
  483. # slow path; we have to ensure immediate symbols are preferred for
  484. # symbol lookups.
  485. # consider the chain: foo (immediate), foo, bar, bar (immediate)
  486. # then bar (immediate) gets replaced with foo (immediate) and the non
  487. # immediate foo is picked! Thus we need to replace it with the first
  488. # slot that has in fact the same identifier stored in it!
  489. var favPos = -1
  490. while data[h] != nil:
  491. if data[h] == n: return
  492. if favPos < 0 and data[h].name.id == n.name.id: favPos = h
  493. h = nextTry(h, high(data))
  494. assert(data[h] == nil)
  495. data[h] = n
  496. if favPos >= 0: swap data[h], data[favPos]
  497. proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
  498. assert prevSym.name.h == newSym.name.h
  499. var h: Hash = prevSym.name.h and high(data)
  500. while data[h] != nil:
  501. if data[h] == prevSym:
  502. data[h] = newSym
  503. return
  504. h = nextTry(h, high(data))
  505. assert false
  506. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  507. symTabReplaceRaw(t.data, prevSym, newSym)
  508. proc strTableEnlarge(t: var TStrTable) =
  509. var n: TSymSeq
  510. newSeq(n, len(t.data) * GrowthFactor)
  511. for i in countup(0, high(t.data)):
  512. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  513. swap(t.data, n)
  514. proc strTableAdd(t: var TStrTable, n: PSym) =
  515. if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
  516. strTableRawInsert(t.data, n)
  517. inc(t.counter)
  518. proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
  519. # returns true if n is already in the string table:
  520. # It is essential that `n` is written nevertheless!
  521. # This way the newest redefinition is picked by the semantic analyses!
  522. assert n.name != nil
  523. var h: Hash = n.name.h and high(t.data)
  524. var replaceSlot = -1
  525. while true:
  526. var it = t.data[h]
  527. if it == nil: break
  528. # Semantic checking can happen multiple times thanks to templates
  529. # and overloading: (var x=@[]; x).mapIt(it).
  530. # So it is possible the very same sym is added multiple
  531. # times to the symbol table which we allow here with the 'it == n' check.
  532. if it.name.id == n.name.id:
  533. if it == n: return false
  534. replaceSlot = h
  535. h = nextTry(h, high(t.data))
  536. if replaceSlot >= 0:
  537. if not onConflictKeepOld:
  538. t.data[replaceSlot] = n # overwrite it with newer definition!
  539. return true # found it
  540. elif mustRehash(len(t.data), t.counter):
  541. strTableEnlarge(t)
  542. strTableRawInsert(t.data, n)
  543. else:
  544. assert(t.data[h] == nil)
  545. t.data[h] = n
  546. inc(t.counter)
  547. result = false
  548. proc strTableGet(t: TStrTable, name: PIdent): PSym =
  549. var h: Hash = name.h and high(t.data)
  550. while true:
  551. result = t.data[h]
  552. if result == nil: break
  553. if result.name.id == name.id: break
  554. h = nextTry(h, high(t.data))
  555. proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  556. ti.h = s.h
  557. ti.name = s
  558. if tab.counter == 0: result = nil
  559. else: result = nextIdentIter(ti, tab)
  560. proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
  561. var h = ti.h and high(tab.data)
  562. var start = h
  563. result = tab.data[h]
  564. while result != nil:
  565. if result.name.id == ti.name.id: break
  566. h = nextTry(h, high(tab.data))
  567. if h == start:
  568. result = nil
  569. break
  570. result = tab.data[h]
  571. ti.h = nextTry(h, high(tab.data))
  572. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  573. excluding: IntSet): PSym =
  574. var h: Hash = ti.h and high(tab.data)
  575. var start = h
  576. result = tab.data[h]
  577. while result != nil:
  578. if result.name.id == ti.name.id and not contains(excluding, result.id):
  579. break
  580. h = nextTry(h, high(tab.data))
  581. if h == start:
  582. result = nil
  583. break
  584. result = tab.data[h]
  585. ti.h = nextTry(h, high(tab.data))
  586. if result != nil and contains(excluding, result.id): result = nil
  587. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  588. excluding: IntSet): PSym =
  589. ti.h = s.h
  590. ti.name = s
  591. if tab.counter == 0: result = nil
  592. else: result = nextIdentExcluding(ti, tab, excluding)
  593. proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
  594. ti.h = 0 # we start by zero ...
  595. if tab.counter == 0:
  596. result = nil # FIX 1: removed endless loop
  597. else:
  598. result = nextIter(ti, tab)
  599. proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
  600. result = nil
  601. while (ti.h <= high(tab.data)):
  602. result = tab.data[ti.h]
  603. inc(ti.h) # ... and increment by one always
  604. if result != nil: break
  605. iterator items*(tab: TStrTable): PSym =
  606. var it: TTabIter
  607. var s = initTabIter(it, tab)
  608. while s != nil:
  609. yield s
  610. s = nextIter(it, tab)
  611. proc hasEmptySlot(data: TIdPairSeq): bool =
  612. for h in countup(0, high(data)):
  613. if data[h].key == nil:
  614. return true
  615. result = false
  616. proc idTableRawGet(t: TIdTable, key: int): int =
  617. var h: Hash
  618. h = key and high(t.data) # start with real hash value
  619. while t.data[h].key != nil:
  620. if t.data[h].key.id == key:
  621. return h
  622. h = nextTry(h, high(t.data))
  623. result = - 1
  624. proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
  625. var index = idTableRawGet(t, key.id)
  626. if index >= 0: result = t.data[index].key == key
  627. else: result = false
  628. proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
  629. var index = idTableRawGet(t, key.id)
  630. if index >= 0: result = t.data[index].val
  631. else: result = nil
  632. proc idTableGet(t: TIdTable, key: int): RootRef =
  633. var index = idTableRawGet(t, key)
  634. if index >= 0: result = t.data[index].val
  635. else: result = nil
  636. iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
  637. for i in 0..high(t.data):
  638. if t.data[i].key != nil:
  639. yield (t.data[i].key.id, t.data[i].val)
  640. proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
  641. var h: Hash
  642. h = key.id and high(data)
  643. while data[h].key != nil:
  644. assert(data[h].key.id != key.id)
  645. h = nextTry(h, high(data))
  646. assert(data[h].key == nil)
  647. data[h].key = key
  648. data[h].val = val
  649. proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
  650. var
  651. index: int
  652. n: TIdPairSeq
  653. index = idTableRawGet(t, key.id)
  654. if index >= 0:
  655. assert(t.data[index].key != nil)
  656. t.data[index].val = val
  657. else:
  658. if mustRehash(len(t.data), t.counter):
  659. newSeq(n, len(t.data) * GrowthFactor)
  660. for i in countup(0, high(t.data)):
  661. if t.data[i].key != nil:
  662. idTableRawInsert(n, t.data[i].key, t.data[i].val)
  663. assert(hasEmptySlot(n))
  664. swap(t.data, n)
  665. idTableRawInsert(t.data, key, val)
  666. inc(t.counter)
  667. iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
  668. for i in 0 .. high(t.data):
  669. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  670. proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
  671. var h: Hash
  672. h = key.id and high(t.data) # start with real hash value
  673. while t.data[h].key != nil:
  674. if t.data[h].key.id == key.id:
  675. return h
  676. h = nextTry(h, high(t.data))
  677. result = - 1
  678. proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
  679. var index: int
  680. index = idNodeTableRawGet(t, key)
  681. if index >= 0: result = t.data[index].val
  682. else: result = nil
  683. proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
  684. if not isNil(t.data):
  685. result = idNodeTableGet(t, key)
  686. proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
  687. var h: Hash
  688. h = key.id and high(data)
  689. while data[h].key != nil:
  690. assert(data[h].key.id != key.id)
  691. h = nextTry(h, high(data))
  692. assert(data[h].key == nil)
  693. data[h].key = key
  694. data[h].val = val
  695. proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  696. var index = idNodeTableRawGet(t, key)
  697. if index >= 0:
  698. assert(t.data[index].key != nil)
  699. t.data[index].val = val
  700. else:
  701. if mustRehash(len(t.data), t.counter):
  702. var n: TIdNodePairSeq
  703. newSeq(n, len(t.data) * GrowthFactor)
  704. for i in countup(0, high(t.data)):
  705. if t.data[i].key != nil:
  706. idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
  707. swap(t.data, n)
  708. idNodeTableRawInsert(t.data, key, val)
  709. inc(t.counter)
  710. proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  711. if isNil(t.data): initIdNodeTable(t)
  712. idNodeTablePut(t, key, val)
  713. iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
  714. for i in 0 .. high(t.data):
  715. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  716. proc initIITable(x: var TIITable) =
  717. x.counter = 0
  718. newSeq(x.data, StartSize)
  719. for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
  720. proc iiTableRawGet(t: TIITable, key: int): int =
  721. var h: Hash
  722. h = key and high(t.data) # start with real hash value
  723. while t.data[h].key != InvalidKey:
  724. if t.data[h].key == key: return h
  725. h = nextTry(h, high(t.data))
  726. result = -1
  727. proc iiTableGet(t: TIITable, key: int): int =
  728. var index = iiTableRawGet(t, key)
  729. if index >= 0: result = t.data[index].val
  730. else: result = InvalidKey
  731. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  732. var h: Hash
  733. h = key and high(data)
  734. while data[h].key != InvalidKey:
  735. assert(data[h].key != key)
  736. h = nextTry(h, high(data))
  737. assert(data[h].key == InvalidKey)
  738. data[h].key = key
  739. data[h].val = val
  740. proc iiTablePut(t: var TIITable, key, val: int) =
  741. var index = iiTableRawGet(t, key)
  742. if index >= 0:
  743. assert(t.data[index].key != InvalidKey)
  744. t.data[index].val = val
  745. else:
  746. if mustRehash(len(t.data), t.counter):
  747. var n: TIIPairSeq
  748. newSeq(n, len(t.data) * GrowthFactor)
  749. for i in countup(0, high(n)): n[i].key = InvalidKey
  750. for i in countup(0, high(t.data)):
  751. if t.data[i].key != InvalidKey:
  752. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  753. swap(t.data, n)
  754. iiTableRawInsert(t.data, key, val)
  755. inc(t.counter)