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