astalgo.nim 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  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 @$2\"" % [rope(n.name.s), rope(
  225. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  226. else:
  227. var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
  228. result = ropeConstr(indent, [rope("kind"),
  229. makeYamlString($n.kind),
  230. rope("name"), makeYamlString(n.name.s),
  231. rope("typ"), typeToYamlAux(conf, n.typ, marker,
  232. indent + 2, maxRecDepth - 1),
  233. rope("info"), lineInfoToStr(conf, n.info),
  234. rope("flags"), flagsToStr(n.flags),
  235. rope("magic"), makeYamlString($n.magic),
  236. rope("ast"), ast, rope("options"),
  237. flagsToStr(n.options), rope("position"),
  238. rope(n.position)])
  239. proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
  240. maxRecDepth: int): Rope =
  241. if n == nil:
  242. result = rope("null")
  243. elif containsOrIncl(marker, n.id):
  244. result = "\"$1 @$2\"" % [rope($n.kind), rope(
  245. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  246. else:
  247. if sonsLen(n) > 0:
  248. result = rope("[")
  249. for i in countup(0, sonsLen(n) - 1):
  250. if i > 0: add(result, ",")
  251. addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
  252. marker, indent + 4, maxRecDepth - 1)])
  253. addf(result, "$N$1]", [rspaces(indent + 2)])
  254. else:
  255. result = rope("null")
  256. result = ropeConstr(indent, [rope("kind"),
  257. makeYamlString($n.kind),
  258. rope("sym"), symToYamlAux(conf, n.sym, marker,
  259. indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(conf, n.n, marker,
  260. indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
  261. rope("callconv"),
  262. makeYamlString(CallingConvToStr[n.callConv]),
  263. rope("size"), rope(n.size),
  264. rope("align"), rope(n.align),
  265. rope("sons"), result])
  266. proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
  267. maxRecDepth: int): Rope =
  268. if n == nil:
  269. result = rope("null")
  270. else:
  271. var istr = rspaces(indent + 2)
  272. result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
  273. if maxRecDepth != 0:
  274. addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  275. case n.kind
  276. of nkCharLit..nkInt64Lit:
  277. addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  278. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  279. addf(result, ",$N$1\"floatVal\": $2",
  280. [istr, rope(n.floatVal.toStrMaxPrecision)])
  281. of nkStrLit..nkTripleStrLit:
  282. addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  283. of nkSym:
  284. addf(result, ",$N$1\"sym\": $2",
  285. [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
  286. of nkIdent:
  287. if n.ident != nil:
  288. addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  289. else:
  290. addf(result, ",$N$1\"ident\": null", [istr])
  291. else:
  292. if sonsLen(n) > 0:
  293. addf(result, ",$N$1\"sons\": [", [istr])
  294. for i in countup(0, sonsLen(n) - 1):
  295. if i > 0: add(result, ",")
  296. addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
  297. marker, indent + 4, maxRecDepth - 1)])
  298. addf(result, "$N$1]", [istr])
  299. addf(result, ",$N$1\"typ\": $2",
  300. [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
  301. addf(result, "$N$1}", [rspaces(indent)])
  302. proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
  303. var marker = initIntSet()
  304. result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
  305. proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
  306. var marker = initIntSet()
  307. result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
  308. proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
  309. var marker = initIntSet()
  310. result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
  311. proc debugTree*(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
  312. proc debugType(conf: ConfigRef; n: PType, maxRecDepth=100): Rope =
  313. if n == nil:
  314. result = rope("null")
  315. else:
  316. result = rope($n.kind)
  317. if n.sym != nil:
  318. add(result, " ")
  319. add(result, n.sym.name.s)
  320. if n.kind in IntegralTypes and n.n != nil:
  321. add(result, ", node: ")
  322. add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true))
  323. if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
  324. add(result, "(")
  325. for i in countup(0, sonsLen(n) - 1):
  326. if i > 0: add(result, ", ")
  327. if n.sons[i] == nil:
  328. add(result, "null")
  329. else:
  330. add(result, debugType(conf, n.sons[i], maxRecDepth-1))
  331. if n.kind == tyObject and n.n != nil:
  332. add(result, ", node: ")
  333. add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true))
  334. add(result, ")")
  335. proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
  336. renderType=false): Rope =
  337. if n == nil:
  338. result = rope("null")
  339. else:
  340. var istr = rspaces(indent + 2)
  341. result = "{$N$1\"kind\": $2" %
  342. [istr, makeYamlString($n.kind)]
  343. when defined(useNodeIds):
  344. addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)])
  345. addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  346. if maxRecDepth != 0:
  347. addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)])
  348. case n.kind
  349. of nkCharLit..nkUInt64Lit:
  350. addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  351. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  352. addf(result, ",$N$1\"floatVal\": $2",
  353. [istr, rope(n.floatVal.toStrMaxPrecision)])
  354. of nkStrLit..nkTripleStrLit:
  355. addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  356. of nkSym:
  357. addf(result, ",$N$1\"sym\": $2_$3",
  358. [istr, rope(n.sym.name.s), rope(n.sym.id)])
  359. # [istr, symToYaml(n.sym, indent, maxRecDepth),
  360. # rope(n.sym.id)])
  361. if renderType and n.sym.typ != nil:
  362. addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.sym.typ, 2)])
  363. of nkIdent:
  364. if n.ident != nil:
  365. addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  366. else:
  367. addf(result, ",$N$1\"ident\": null", [istr])
  368. else:
  369. if renderType and n.typ != nil:
  370. addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.typ, 2)])
  371. if sonsLen(n) > 0:
  372. addf(result, ",$N$1\"sons\": [", [istr])
  373. for i in countup(0, sonsLen(n) - 1):
  374. if i > 0: add(result, ",")
  375. addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(conf, n.sons[i],
  376. indent + 4, maxRecDepth - 1, renderType)])
  377. addf(result, "$N$1]", [istr])
  378. addf(result, "$N$1}", [rspaces(indent)])
  379. when declared(echo):
  380. proc debug(n: PSym; conf: ConfigRef) =
  381. if n == nil:
  382. echo("null")
  383. elif n.kind == skUnknown:
  384. echo("skUnknown")
  385. else:
  386. #writeLine(stdout, $symToYaml(n, 0, 1))
  387. echo("$1_$2: $3, $4, $5, $6" % [
  388. n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
  389. $lineInfoToStr(conf, n.info), $n.kind])
  390. proc debug(n: PType; conf: ConfigRef) =
  391. echo($debugType(conf, n))
  392. proc debug(n: PNode; conf: ConfigRef) =
  393. echo($debugTree(conf, n, 0, 100))
  394. proc nextTry(h, maxHash: Hash): Hash =
  395. result = ((5 * h) + 1) and maxHash
  396. # For any initial h in range(maxHash), repeating that maxHash times
  397. # generates each int in range(maxHash) exactly once (see any text on
  398. # random-number generation for proof).
  399. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
  400. # returns true whether n is in t
  401. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  402. while t.data[h] != nil:
  403. if t.data[h] == obj:
  404. return true
  405. h = nextTry(h, high(t.data))
  406. result = false
  407. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  408. var h: Hash = hashNode(obj) and high(data)
  409. while data[h] != nil:
  410. assert(data[h] != obj)
  411. h = nextTry(h, high(data))
  412. assert(data[h] == nil)
  413. data[h] = obj
  414. proc objectSetEnlarge(t: var TObjectSet) =
  415. var n: TObjectSeq
  416. newSeq(n, len(t.data) * GrowthFactor)
  417. for i in countup(0, high(t.data)):
  418. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  419. swap(t.data, n)
  420. proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
  421. if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
  422. objectSetRawInsert(t.data, obj)
  423. inc(t.counter)
  424. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
  425. # returns true if obj is already in the string table:
  426. var h: Hash = hashNode(obj) and high(t.data)
  427. while true:
  428. var it = t.data[h]
  429. if it == nil: break
  430. if it == obj:
  431. return true # found it
  432. h = nextTry(h, high(t.data))
  433. if mustRehash(len(t.data), t.counter):
  434. objectSetEnlarge(t)
  435. objectSetRawInsert(t.data, obj)
  436. else:
  437. assert(t.data[h] == nil)
  438. t.data[h] = obj
  439. inc(t.counter)
  440. result = false
  441. proc strTableContains*(t: TStrTable, n: PSym): bool =
  442. var h: Hash = n.name.h and high(t.data) # start with real hash value
  443. while t.data[h] != nil:
  444. if (t.data[h] == n):
  445. return true
  446. h = nextTry(h, high(t.data))
  447. result = false
  448. proc strTableRawInsert(data: var TSymSeq, n: PSym) =
  449. var h: Hash = n.name.h and high(data)
  450. if sfImmediate notin n.flags:
  451. # fast path:
  452. while data[h] != nil:
  453. if data[h] == n:
  454. # allowed for 'export' feature:
  455. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  456. return
  457. h = nextTry(h, high(data))
  458. assert(data[h] == nil)
  459. data[h] = n
  460. else:
  461. # slow path; we have to ensure immediate symbols are preferred for
  462. # symbol lookups.
  463. # consider the chain: foo (immediate), foo, bar, bar (immediate)
  464. # then bar (immediate) gets replaced with foo (immediate) and the non
  465. # immediate foo is picked! Thus we need to replace it with the first
  466. # slot that has in fact the same identifier stored in it!
  467. var favPos = -1
  468. while data[h] != nil:
  469. if data[h] == n: return
  470. if favPos < 0 and data[h].name.id == n.name.id: favPos = h
  471. h = nextTry(h, high(data))
  472. assert(data[h] == nil)
  473. data[h] = n
  474. if favPos >= 0: swap data[h], data[favPos]
  475. proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
  476. assert prevSym.name.h == newSym.name.h
  477. var h: Hash = prevSym.name.h and high(data)
  478. while data[h] != nil:
  479. if data[h] == prevSym:
  480. data[h] = newSym
  481. return
  482. h = nextTry(h, high(data))
  483. assert false
  484. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  485. symTabReplaceRaw(t.data, prevSym, newSym)
  486. proc strTableEnlarge(t: var TStrTable) =
  487. var n: TSymSeq
  488. newSeq(n, len(t.data) * GrowthFactor)
  489. for i in countup(0, high(t.data)):
  490. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  491. swap(t.data, n)
  492. proc strTableAdd*(t: var TStrTable, n: PSym) =
  493. if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
  494. strTableRawInsert(t.data, n)
  495. inc(t.counter)
  496. proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
  497. onConflictKeepOld = false): PSym =
  498. # returns true if n is already in the string table:
  499. # It is essential that `n` is written nevertheless!
  500. # This way the newest redefinition is picked by the semantic analyses!
  501. assert n.name != nil
  502. var h: Hash = n.name.h and high(t.data)
  503. var replaceSlot = -1
  504. while true:
  505. var it = t.data[h]
  506. if it == nil: break
  507. # Semantic checking can happen multiple times thanks to templates
  508. # and overloading: (var x=@[]; x).mapIt(it).
  509. # So it is possible the very same sym is added multiple
  510. # times to the symbol table which we allow here with the 'it == n' check.
  511. if it.name.id == n.name.id:
  512. if it == n: return nil
  513. replaceSlot = h
  514. h = nextTry(h, high(t.data))
  515. if replaceSlot >= 0:
  516. if not onConflictKeepOld:
  517. t.data[replaceSlot] = n # overwrite it with newer definition!
  518. return t.data[replaceSlot] # found it
  519. elif mustRehash(len(t.data), t.counter):
  520. strTableEnlarge(t)
  521. strTableRawInsert(t.data, n)
  522. else:
  523. assert(t.data[h] == nil)
  524. t.data[h] = n
  525. inc(t.counter)
  526. result = nil
  527. proc strTableIncl*(t: var TStrTable, n: PSym;
  528. onConflictKeepOld = false): bool {.discardable.} =
  529. result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
  530. proc strTableGet*(t: TStrTable, name: PIdent): PSym =
  531. var h: Hash = name.h and high(t.data)
  532. while true:
  533. result = t.data[h]
  534. if result == nil: break
  535. if result.name.id == name.id: break
  536. h = nextTry(h, high(t.data))
  537. type
  538. TIdentIter* = object # iterator over all syms with same identifier
  539. h*: Hash # current hash
  540. name*: PIdent
  541. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
  542. var h = ti.h and high(tab.data)
  543. var start = h
  544. result = tab.data[h]
  545. while result != nil:
  546. if result.name.id == ti.name.id: break
  547. h = nextTry(h, high(tab.data))
  548. if h == start:
  549. result = nil
  550. break
  551. result = tab.data[h]
  552. ti.h = nextTry(h, high(tab.data))
  553. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  554. ti.h = s.h
  555. ti.name = s
  556. if tab.counter == 0: result = nil
  557. else: result = nextIdentIter(ti, tab)
  558. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  559. excluding: IntSet): PSym =
  560. var h: Hash = ti.h and high(tab.data)
  561. var start = h
  562. result = tab.data[h]
  563. while result != nil:
  564. if result.name.id == ti.name.id and not contains(excluding, result.id):
  565. 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. if result != nil and contains(excluding, result.id): result = nil
  573. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  574. excluding: IntSet): PSym =
  575. ti.h = s.h
  576. ti.name = s
  577. if tab.counter == 0: result = nil
  578. else: result = nextIdentExcluding(ti, tab, excluding)
  579. type
  580. TTabIter* = object
  581. h: Hash
  582. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
  583. # usage:
  584. # var
  585. # i: TTabIter
  586. # s: PSym
  587. # s = InitTabIter(i, table)
  588. # while s != nil:
  589. # ...
  590. # s = NextIter(i, table)
  591. #
  592. result = nil
  593. while (ti.h <= high(tab.data)):
  594. result = tab.data[ti.h]
  595. inc(ti.h) # ... and increment by one always
  596. if result != nil: break
  597. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
  598. ti.h = 0
  599. if tab.counter == 0:
  600. result = nil
  601. else:
  602. result = nextIter(ti, tab)
  603. iterator items*(tab: TStrTable): PSym =
  604. var it: TTabIter
  605. var s = initTabIter(it, tab)
  606. while s != nil:
  607. yield s
  608. s = nextIter(it, tab)
  609. proc hasEmptySlot(data: TIdPairSeq): bool =
  610. for h in countup(0, high(data)):
  611. if data[h].key == nil:
  612. return true
  613. result = false
  614. proc idTableRawGet(t: TIdTable, key: int): int =
  615. var h: Hash
  616. h = key and high(t.data) # start with real hash value
  617. while t.data[h].key != nil:
  618. if t.data[h].key.id == key:
  619. return h
  620. h = nextTry(h, high(t.data))
  621. result = - 1
  622. proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
  623. var index = idTableRawGet(t, key.id)
  624. if index >= 0: result = t.data[index].key == key
  625. else: result = false
  626. proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
  627. var index = idTableRawGet(t, key.id)
  628. if index >= 0: result = t.data[index].val
  629. else: result = nil
  630. proc idTableGet(t: TIdTable, key: int): RootRef =
  631. var index = idTableRawGet(t, key)
  632. if index >= 0: result = t.data[index].val
  633. else: result = nil
  634. iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
  635. for i in 0..high(t.data):
  636. if t.data[i].key != nil:
  637. yield (t.data[i].key.id, t.data[i].val)
  638. proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
  639. var h: Hash
  640. h = key.id and high(data)
  641. while data[h].key != nil:
  642. assert(data[h].key.id != key.id)
  643. h = nextTry(h, high(data))
  644. assert(data[h].key == nil)
  645. data[h].key = key
  646. data[h].val = val
  647. proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
  648. var
  649. index: int
  650. n: TIdPairSeq
  651. index = idTableRawGet(t, key.id)
  652. if index >= 0:
  653. assert(t.data[index].key != nil)
  654. t.data[index].val = val
  655. else:
  656. if mustRehash(len(t.data), t.counter):
  657. newSeq(n, len(t.data) * GrowthFactor)
  658. for i in countup(0, high(t.data)):
  659. if t.data[i].key != nil:
  660. idTableRawInsert(n, t.data[i].key, t.data[i].val)
  661. assert(hasEmptySlot(n))
  662. swap(t.data, n)
  663. idTableRawInsert(t.data, key, val)
  664. inc(t.counter)
  665. iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
  666. for i in 0 .. high(t.data):
  667. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  668. proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
  669. var h: Hash
  670. h = key.id and high(t.data) # start with real hash value
  671. while t.data[h].key != nil:
  672. if t.data[h].key.id == key.id:
  673. return h
  674. h = nextTry(h, high(t.data))
  675. result = - 1
  676. proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
  677. var index: int
  678. index = idNodeTableRawGet(t, key)
  679. if index >= 0: result = t.data[index].val
  680. else: result = nil
  681. proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
  682. var h: Hash
  683. h = key.id and high(data)
  684. while data[h].key != nil:
  685. assert(data[h].key.id != key.id)
  686. h = nextTry(h, high(data))
  687. assert(data[h].key == nil)
  688. data[h].key = key
  689. data[h].val = val
  690. proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  691. var index = idNodeTableRawGet(t, key)
  692. if index >= 0:
  693. assert(t.data[index].key != nil)
  694. t.data[index].val = val
  695. else:
  696. if mustRehash(len(t.data), t.counter):
  697. var n: TIdNodePairSeq
  698. newSeq(n, len(t.data) * GrowthFactor)
  699. for i in countup(0, high(t.data)):
  700. if t.data[i].key != nil:
  701. idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
  702. swap(t.data, n)
  703. idNodeTableRawInsert(t.data, key, val)
  704. inc(t.counter)
  705. iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
  706. for i in 0 .. high(t.data):
  707. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  708. proc initIITable(x: var TIITable) =
  709. x.counter = 0
  710. newSeq(x.data, StartSize)
  711. for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
  712. proc iiTableRawGet(t: TIITable, key: int): int =
  713. var h: Hash
  714. h = key and high(t.data) # start with real hash value
  715. while t.data[h].key != InvalidKey:
  716. if t.data[h].key == key: return h
  717. h = nextTry(h, high(t.data))
  718. result = -1
  719. proc iiTableGet(t: TIITable, key: int): int =
  720. var index = iiTableRawGet(t, key)
  721. if index >= 0: result = t.data[index].val
  722. else: result = InvalidKey
  723. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  724. var h: Hash
  725. h = key and high(data)
  726. while data[h].key != InvalidKey:
  727. assert(data[h].key != key)
  728. h = nextTry(h, high(data))
  729. assert(data[h].key == InvalidKey)
  730. data[h].key = key
  731. data[h].val = val
  732. proc iiTablePut(t: var TIITable, key, val: int) =
  733. var index = iiTableRawGet(t, key)
  734. if index >= 0:
  735. assert(t.data[index].key != InvalidKey)
  736. t.data[index].val = val
  737. else:
  738. if mustRehash(len(t.data), t.counter):
  739. var n: TIIPairSeq
  740. newSeq(n, len(t.data) * GrowthFactor)
  741. for i in countup(0, high(n)): n[i].key = InvalidKey
  742. for i in countup(0, high(t.data)):
  743. if t.data[i].key != InvalidKey:
  744. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  745. swap(t.data, n)
  746. iiTableRawInsert(t.data, key, val)
  747. inc(t.counter)