astalgo.nim 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  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 symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
  210. maxRecDepth: int): Rope =
  211. if n == nil:
  212. result = rope("null")
  213. elif containsOrIncl(marker, n.id):
  214. result = "\"$1\"" % [rope(n.name.s)]
  215. else:
  216. var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
  217. #rope("typ"), typeToYamlAux(conf, n.typ, marker,
  218. # indent + 2, maxRecDepth - 1),
  219. let istr = rspaces(indent + 2)
  220. result = rope("{")
  221. addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
  222. addf(result, "$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
  223. addf(result, "$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
  224. if conf != nil:
  225. # if we don't pass the config, we probably don't care about the line info
  226. addf(result, "$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  227. if card(n.flags) > 0:
  228. addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
  229. addf(result, "$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
  230. addf(result, "$N$1\"ast\": $2", [istr, ast])
  231. addf(result, "$N$1\"options\": $2", [istr, flagsToStr(n.options)])
  232. addf(result, "$N$1\"position\": $2", [istr, rope(n.position)])
  233. addf(result, "$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
  234. addf(result, "$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
  235. if card(n.loc.flags) > 0:
  236. addf(result, "$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
  237. addf(result, "$N$1\"r\": $2", [istr, n.loc.r])
  238. addf(result, "$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
  239. addf(result, "$N$1}", [rspaces(indent)])
  240. proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
  241. maxRecDepth: int): Rope =
  242. var sonsRope: Rope
  243. if n == nil:
  244. sonsRope = rope("null")
  245. elif containsOrIncl(marker, n.id):
  246. sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
  247. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  248. else:
  249. if sonsLen(n) > 0:
  250. sonsRope = rope("[")
  251. for i in countup(0, sonsLen(n) - 1):
  252. if i > 0: add(sonsRope, ",")
  253. addf(sonsRope, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i],
  254. marker, indent + 4, maxRecDepth - 1)])
  255. addf(sonsRope, "$N$1]", [rspaces(indent + 2)])
  256. else:
  257. sonsRope = rope("null")
  258. let istr = rspaces(indent + 2)
  259. result = rope("{")
  260. addf(result, "$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
  261. addf(result, "$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
  262. addf(result, "$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
  263. if card(n.flags) > 0:
  264. addf(result, "$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
  265. addf(result, "$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
  266. addf(result, "$N$1\"size\": $2", [istr, rope(n.size)])
  267. addf(result, "$N$1\"align\": $2", [istr, rope(n.align)])
  268. addf(result, "$N$1\"sons\": $2", [istr, sonsRope])
  269. proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
  270. maxRecDepth: int): Rope =
  271. if n == nil:
  272. result = rope("null")
  273. else:
  274. var istr = rspaces(indent + 2)
  275. result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
  276. if maxRecDepth != 0:
  277. if conf != nil:
  278. addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  279. case n.kind
  280. of nkCharLit..nkInt64Lit:
  281. addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  282. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  283. addf(result, ",$N$1\"floatVal\": $2",
  284. [istr, rope(n.floatVal.toStrMaxPrecision)])
  285. of nkStrLit..nkTripleStrLit:
  286. addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  287. of nkSym:
  288. addf(result, ",$N$1\"sym\": $2",
  289. [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
  290. of nkIdent:
  291. if n.ident != nil:
  292. addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  293. else:
  294. addf(result, ",$N$1\"ident\": null", [istr])
  295. else:
  296. if sonsLen(n) > 0:
  297. addf(result, ",$N$1\"sons\": [", [istr])
  298. for i in countup(0, sonsLen(n) - 1):
  299. if i > 0: add(result, ",")
  300. addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i],
  301. marker, indent + 4, maxRecDepth - 1)])
  302. addf(result, "$N$1]", [istr])
  303. addf(result, ",$N$1\"typ\": $2",
  304. [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
  305. addf(result, "$N$1}", [rspaces(indent)])
  306. proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
  307. var marker = initIntSet()
  308. result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
  309. proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
  310. var marker = initIntSet()
  311. result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
  312. proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
  313. var marker = initIntSet()
  314. result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
  315. import tables
  316. const backrefStyle = "\e[90m"
  317. const enumStyle = "\e[34m"
  318. const numberStyle = "\e[33m"
  319. const stringStyle = "\e[32m"
  320. const resetStyle = "\e[0m"
  321. type
  322. DebugPrinter = object
  323. conf: ConfigRef
  324. visited: Table[pointer, int]
  325. renderSymType: bool
  326. indent: int
  327. currentLine: int
  328. firstItem: bool
  329. useColor: bool
  330. res: string
  331. proc indentMore(this: var DebugPrinter) =
  332. this.indent += 2
  333. proc indentLess(this: var DebugPrinter) =
  334. this.indent -= 2
  335. proc newlineAndIndent(this: var DebugPrinter) =
  336. this.res.add "\n"
  337. this.currentLine += 1
  338. for i in 0 ..< this.indent:
  339. this.res.add ' '
  340. proc openCurly(this: var DebugPrinter) =
  341. this.res.add "{"
  342. this.indentMore
  343. this.firstItem = true
  344. proc closeCurly(this: var DebugPrinter) =
  345. this.indentLess
  346. this.newlineAndIndent
  347. this.res.add "}"
  348. proc comma(this: var DebugPrinter) =
  349. this.res.add ", "
  350. proc openBracket(this: var DebugPrinter) =
  351. this.res.add "["
  352. #this.indentMore
  353. proc closeBracket(this: var DebugPrinter) =
  354. #this.indentLess
  355. this.res.add "]"
  356. proc key(this: var DebugPrinter; key: string) =
  357. if not this.firstItem:
  358. this.res.add ","
  359. this.firstItem = false
  360. this.newlineAndIndent
  361. this.res.add "\""
  362. this.res.add key
  363. this.res.add "\": "
  364. proc value(this: var DebugPrinter; value: string) =
  365. if this.useColor:
  366. this.res.add stringStyle
  367. this.res.add "\""
  368. this.res.add value
  369. this.res.add "\""
  370. if this.useColor:
  371. this.res.add resetStyle
  372. proc value(this: var DebugPrinter; value: BiggestInt) =
  373. if this.useColor:
  374. this.res.add numberStyle
  375. this.res.add value
  376. if this.useColor:
  377. this.res.add resetStyle
  378. proc value[T: enum](this: var DebugPrinter; value: T) =
  379. if this.useColor:
  380. this.res.add enumStyle
  381. this.res.add "\""
  382. this.res.add $value
  383. this.res.add "\""
  384. if this.useColor:
  385. this.res.add resetStyle
  386. proc value[T: enum](this: var DebugPrinter; value: set[T]) =
  387. this.openBracket
  388. let high = card(value)-1
  389. var i = 0
  390. for v in value:
  391. this.value v
  392. if i != high:
  393. this.comma
  394. inc i
  395. this.closeBracket
  396. template earlyExit(this: var DebugPrinter; n: PType | PNode | PSym) =
  397. if n == nil:
  398. this.res.add "null"
  399. return
  400. let index = this.visited.getOrDefault(cast[pointer](n), -1)
  401. if index < 0:
  402. this.visited[cast[pointer](n)] = this.currentLine
  403. else:
  404. if this.useColor:
  405. this.res.add backrefStyle
  406. this.res.add "<defined "
  407. this.res.add(this.currentLine - index)
  408. this.res.add " lines upwards>"
  409. if this.useColor:
  410. this.res.add resetStyle
  411. return
  412. proc value(this: var DebugPrinter; value: PType): void
  413. proc value(this: var DebugPrinter; value: PNode): void
  414. proc value(this: var DebugPrinter; value: PSym): void =
  415. earlyExit(this, value)
  416. this.openCurly
  417. this.key("kind")
  418. this.value(value.kind)
  419. this.key("name")
  420. this.value(value.name.s)
  421. this.key("id")
  422. this.value(value.id)
  423. if value.kind in {skField, skEnumField, skParam}:
  424. this.key("position")
  425. this.value(value.position)
  426. if card(value.flags) > 0:
  427. this.key("flags")
  428. this.value(value.flags)
  429. if this.renderSymType and value.typ != nil:
  430. this.key "typ"
  431. this.value(value.typ)
  432. this.closeCurly
  433. proc value(this: var DebugPrinter; value: PType): void =
  434. earlyExit(this, value)
  435. this.openCurly
  436. this.key "kind"
  437. this.value value.kind
  438. this.key "id"
  439. this.value value.id
  440. if value.sym != nil:
  441. this.key "sym"
  442. this.value value.sym
  443. #this.value value.sym.name.s
  444. if card(value.flags) > 0:
  445. this.key "flags"
  446. this.value value.flags
  447. if value.kind in IntegralTypes and value.n != nil:
  448. this.key "n"
  449. this.value value.n
  450. if sonsLen(value) > 0:
  451. this.key "sons"
  452. this.openBracket
  453. for i in 0 ..< sonsLen(value):
  454. this.value value.sons[i]
  455. if i != sonsLen(value) - 1:
  456. this.comma
  457. this.closeBracket
  458. if value.n != nil:
  459. this.key "n"
  460. this.value value.n
  461. this.closeCurly
  462. proc value(this: var DebugPrinter; value: PNode): void =
  463. earlyExit(this, value)
  464. this.openCurly
  465. this.key "kind"
  466. this.value value.kind
  467. when defined(useNodeIds):
  468. this.key "id"
  469. this.value value.id
  470. if this.conf != nil:
  471. this.key "info"
  472. this.value $lineInfoToStr(this.conf, value.info)
  473. if card(value.flags) > 0:
  474. this.key "flags"
  475. this.value value.flags
  476. case value.kind
  477. of nkCharLit..nkUInt64Lit:
  478. this.key "intVal"
  479. this.value value.intVal
  480. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  481. this.key "floatVal"
  482. this.value value.floatVal.toStrMaxPrecision
  483. of nkStrLit..nkTripleStrLit:
  484. this.key "strVal"
  485. this.value value.strVal
  486. of nkSym:
  487. this.key "sym"
  488. this.value value.sym
  489. #this.value value.sym.name.s
  490. of nkIdent:
  491. if value.ident != nil:
  492. this.key "ident"
  493. this.value value.ident.s
  494. else:
  495. if this.renderSymType and value.typ != nil:
  496. this.key "typ"
  497. this.value value.typ
  498. if sonsLen(value) > 0:
  499. this.key "sons"
  500. this.openBracket
  501. for i in 0 ..< sonsLen(value):
  502. this.value value.sons[i]
  503. if i != sonsLen(value) - 1:
  504. this.comma
  505. this.closeBracket
  506. this.closeCurly
  507. when declared(echo):
  508. proc debug(n: PSym; conf: ConfigRef) =
  509. var this: DebugPrinter
  510. this.visited = initTable[pointer, int]()
  511. this.renderSymType = true
  512. this.useColor = not defined(windows)
  513. this.value(n)
  514. echo($this.res)
  515. proc debug(n: PType; conf: ConfigRef) =
  516. var this: DebugPrinter
  517. this.visited = initTable[pointer, int]()
  518. this.renderSymType = true
  519. this.useColor = not defined(windows)
  520. this.value(n)
  521. echo($this.res)
  522. proc debug(n: PNode; conf: ConfigRef) =
  523. var this: DebugPrinter
  524. this.visited = initTable[pointer, int]()
  525. this.renderSymType = true
  526. this.useColor = not defined(windows)
  527. this.value(n)
  528. echo($this.res)
  529. proc nextTry(h, maxHash: Hash): Hash =
  530. result = ((5 * h) + 1) and maxHash
  531. # For any initial h in range(maxHash), repeating that maxHash times
  532. # generates each int in range(maxHash) exactly once (see any text on
  533. # random-number generation for proof).
  534. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
  535. # returns true whether n is in t
  536. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  537. while t.data[h] != nil:
  538. if t.data[h] == obj:
  539. return true
  540. h = nextTry(h, high(t.data))
  541. result = false
  542. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  543. var h: Hash = hashNode(obj) and high(data)
  544. while data[h] != nil:
  545. assert(data[h] != obj)
  546. h = nextTry(h, high(data))
  547. assert(data[h] == nil)
  548. data[h] = obj
  549. proc objectSetEnlarge(t: var TObjectSet) =
  550. var n: TObjectSeq
  551. newSeq(n, len(t.data) * GrowthFactor)
  552. for i in countup(0, high(t.data)):
  553. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  554. swap(t.data, n)
  555. proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
  556. if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
  557. objectSetRawInsert(t.data, obj)
  558. inc(t.counter)
  559. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
  560. # returns true if obj is already in the string table:
  561. var h: Hash = hashNode(obj) and high(t.data)
  562. while true:
  563. var it = t.data[h]
  564. if it == nil: break
  565. if it == obj:
  566. return true # found it
  567. h = nextTry(h, high(t.data))
  568. if mustRehash(len(t.data), t.counter):
  569. objectSetEnlarge(t)
  570. objectSetRawInsert(t.data, obj)
  571. else:
  572. assert(t.data[h] == nil)
  573. t.data[h] = obj
  574. inc(t.counter)
  575. result = false
  576. proc strTableContains*(t: TStrTable, n: PSym): bool =
  577. var h: Hash = n.name.h and high(t.data) # start with real hash value
  578. while t.data[h] != nil:
  579. if (t.data[h] == n):
  580. return true
  581. h = nextTry(h, high(t.data))
  582. result = false
  583. proc strTableRawInsert(data: var seq[PSym], n: PSym) =
  584. var h: Hash = n.name.h and high(data)
  585. if sfImmediate notin n.flags:
  586. # fast path:
  587. while data[h] != nil:
  588. if data[h] == n:
  589. # allowed for 'export' feature:
  590. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  591. return
  592. h = nextTry(h, high(data))
  593. assert(data[h] == nil)
  594. data[h] = n
  595. else:
  596. # slow path; we have to ensure immediate symbols are preferred for
  597. # symbol lookups.
  598. # consider the chain: foo (immediate), foo, bar, bar (immediate)
  599. # then bar (immediate) gets replaced with foo (immediate) and the non
  600. # immediate foo is picked! Thus we need to replace it with the first
  601. # slot that has in fact the same identifier stored in it!
  602. var favPos = -1
  603. while data[h] != nil:
  604. if data[h] == n: return
  605. if favPos < 0 and data[h].name.id == n.name.id: favPos = h
  606. h = nextTry(h, high(data))
  607. assert(data[h] == nil)
  608. data[h] = n
  609. if favPos >= 0: swap data[h], data[favPos]
  610. proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
  611. assert prevSym.name.h == newSym.name.h
  612. var h: Hash = prevSym.name.h and high(data)
  613. while data[h] != nil:
  614. if data[h] == prevSym:
  615. data[h] = newSym
  616. return
  617. h = nextTry(h, high(data))
  618. assert false
  619. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  620. symTabReplaceRaw(t.data, prevSym, newSym)
  621. proc strTableEnlarge(t: var TStrTable) =
  622. var n: seq[PSym]
  623. newSeq(n, len(t.data) * GrowthFactor)
  624. for i in countup(0, high(t.data)):
  625. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  626. swap(t.data, n)
  627. proc strTableAdd*(t: var TStrTable, n: PSym) =
  628. if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
  629. strTableRawInsert(t.data, n)
  630. inc(t.counter)
  631. proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
  632. onConflictKeepOld = false): PSym =
  633. # returns true if n is already in the string table:
  634. # It is essential that `n` is written nevertheless!
  635. # This way the newest redefinition is picked by the semantic analyses!
  636. assert n.name != nil
  637. var h: Hash = n.name.h and high(t.data)
  638. var replaceSlot = -1
  639. while true:
  640. var it = t.data[h]
  641. if it == nil: break
  642. # Semantic checking can happen multiple times thanks to templates
  643. # and overloading: (var x=@[]; x).mapIt(it).
  644. # So it is possible the very same sym is added multiple
  645. # times to the symbol table which we allow here with the 'it == n' check.
  646. if it.name.id == n.name.id:
  647. if it == n: return nil
  648. replaceSlot = h
  649. h = nextTry(h, high(t.data))
  650. if replaceSlot >= 0:
  651. if not onConflictKeepOld:
  652. t.data[replaceSlot] = n # overwrite it with newer definition!
  653. return t.data[replaceSlot] # found it
  654. elif mustRehash(len(t.data), t.counter):
  655. strTableEnlarge(t)
  656. strTableRawInsert(t.data, n)
  657. else:
  658. assert(t.data[h] == nil)
  659. t.data[h] = n
  660. inc(t.counter)
  661. result = nil
  662. proc strTableIncl*(t: var TStrTable, n: PSym;
  663. onConflictKeepOld = false): bool {.discardable.} =
  664. result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
  665. proc strTableGet*(t: TStrTable, name: PIdent): PSym =
  666. var h: Hash = name.h and high(t.data)
  667. while true:
  668. result = t.data[h]
  669. if result == nil: break
  670. if result.name.id == name.id: break
  671. h = nextTry(h, high(t.data))
  672. type
  673. TIdentIter* = object # iterator over all syms with same identifier
  674. h*: Hash # current hash
  675. name*: PIdent
  676. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
  677. var h = ti.h and high(tab.data)
  678. var start = h
  679. result = tab.data[h]
  680. while result != nil:
  681. if result.name.id == ti.name.id: break
  682. h = nextTry(h, high(tab.data))
  683. if h == start:
  684. result = nil
  685. break
  686. result = tab.data[h]
  687. ti.h = nextTry(h, high(tab.data))
  688. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  689. ti.h = s.h
  690. ti.name = s
  691. if tab.counter == 0: result = nil
  692. else: result = nextIdentIter(ti, tab)
  693. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  694. excluding: IntSet): PSym =
  695. var h: Hash = ti.h and high(tab.data)
  696. var start = h
  697. result = tab.data[h]
  698. while result != nil:
  699. if result.name.id == ti.name.id and not contains(excluding, result.id):
  700. break
  701. h = nextTry(h, high(tab.data))
  702. if h == start:
  703. result = nil
  704. break
  705. result = tab.data[h]
  706. ti.h = nextTry(h, high(tab.data))
  707. if result != nil and contains(excluding, result.id): result = nil
  708. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  709. excluding: IntSet): PSym =
  710. ti.h = s.h
  711. ti.name = s
  712. if tab.counter == 0: result = nil
  713. else: result = nextIdentExcluding(ti, tab, excluding)
  714. type
  715. TTabIter* = object
  716. h: Hash
  717. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
  718. # usage:
  719. # var
  720. # i: TTabIter
  721. # s: PSym
  722. # s = InitTabIter(i, table)
  723. # while s != nil:
  724. # ...
  725. # s = NextIter(i, table)
  726. #
  727. result = nil
  728. while (ti.h <= high(tab.data)):
  729. result = tab.data[ti.h]
  730. inc(ti.h) # ... and increment by one always
  731. if result != nil: break
  732. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
  733. ti.h = 0
  734. if tab.counter == 0:
  735. result = nil
  736. else:
  737. result = nextIter(ti, tab)
  738. iterator items*(tab: TStrTable): PSym =
  739. var it: TTabIter
  740. var s = initTabIter(it, tab)
  741. while s != nil:
  742. yield s
  743. s = nextIter(it, tab)
  744. proc hasEmptySlot(data: TIdPairSeq): bool =
  745. for h in countup(0, high(data)):
  746. if data[h].key == nil:
  747. return true
  748. result = false
  749. proc idTableRawGet(t: TIdTable, key: int): int =
  750. var h: Hash
  751. h = key and high(t.data) # start with real hash value
  752. while t.data[h].key != nil:
  753. if t.data[h].key.id == key:
  754. return h
  755. h = nextTry(h, high(t.data))
  756. result = - 1
  757. proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
  758. var index = idTableRawGet(t, key.id)
  759. if index >= 0: result = t.data[index].key == key
  760. else: result = false
  761. proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
  762. var index = idTableRawGet(t, key.id)
  763. if index >= 0: result = t.data[index].val
  764. else: result = nil
  765. proc idTableGet(t: TIdTable, key: int): RootRef =
  766. var index = idTableRawGet(t, key)
  767. if index >= 0: result = t.data[index].val
  768. else: result = nil
  769. iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
  770. for i in 0..high(t.data):
  771. if t.data[i].key != nil:
  772. yield (t.data[i].key.id, t.data[i].val)
  773. proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
  774. var h: Hash
  775. h = key.id and high(data)
  776. while data[h].key != nil:
  777. assert(data[h].key.id != key.id)
  778. h = nextTry(h, high(data))
  779. assert(data[h].key == nil)
  780. data[h].key = key
  781. data[h].val = val
  782. proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
  783. var
  784. index: int
  785. n: TIdPairSeq
  786. index = idTableRawGet(t, key.id)
  787. if index >= 0:
  788. assert(t.data[index].key != nil)
  789. t.data[index].val = val
  790. else:
  791. if mustRehash(len(t.data), t.counter):
  792. newSeq(n, len(t.data) * GrowthFactor)
  793. for i in countup(0, high(t.data)):
  794. if t.data[i].key != nil:
  795. idTableRawInsert(n, t.data[i].key, t.data[i].val)
  796. assert(hasEmptySlot(n))
  797. swap(t.data, n)
  798. idTableRawInsert(t.data, key, val)
  799. inc(t.counter)
  800. iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
  801. for i in 0 .. high(t.data):
  802. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  803. proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
  804. var h: Hash
  805. h = key.id and high(t.data) # start with real hash value
  806. while t.data[h].key != nil:
  807. if t.data[h].key.id == key.id:
  808. return h
  809. h = nextTry(h, high(t.data))
  810. result = - 1
  811. proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
  812. var index: int
  813. index = idNodeTableRawGet(t, key)
  814. if index >= 0: result = t.data[index].val
  815. else: result = nil
  816. proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
  817. var h: Hash
  818. h = key.id and high(data)
  819. while data[h].key != nil:
  820. assert(data[h].key.id != key.id)
  821. h = nextTry(h, high(data))
  822. assert(data[h].key == nil)
  823. data[h].key = key
  824. data[h].val = val
  825. proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  826. var index = idNodeTableRawGet(t, key)
  827. if index >= 0:
  828. assert(t.data[index].key != nil)
  829. t.data[index].val = val
  830. else:
  831. if mustRehash(len(t.data), t.counter):
  832. var n: TIdNodePairSeq
  833. newSeq(n, len(t.data) * GrowthFactor)
  834. for i in countup(0, high(t.data)):
  835. if t.data[i].key != nil:
  836. idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
  837. swap(t.data, n)
  838. idNodeTableRawInsert(t.data, key, val)
  839. inc(t.counter)
  840. iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
  841. for i in 0 .. high(t.data):
  842. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  843. proc initIITable(x: var TIITable) =
  844. x.counter = 0
  845. newSeq(x.data, StartSize)
  846. for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
  847. proc iiTableRawGet(t: TIITable, key: int): int =
  848. var h: Hash
  849. h = key and high(t.data) # start with real hash value
  850. while t.data[h].key != InvalidKey:
  851. if t.data[h].key == key: return h
  852. h = nextTry(h, high(t.data))
  853. result = -1
  854. proc iiTableGet(t: TIITable, key: int): int =
  855. var index = iiTableRawGet(t, key)
  856. if index >= 0: result = t.data[index].val
  857. else: result = InvalidKey
  858. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  859. var h: Hash
  860. h = key and high(data)
  861. while data[h].key != InvalidKey:
  862. assert(data[h].key != key)
  863. h = nextTry(h, high(data))
  864. assert(data[h].key == InvalidKey)
  865. data[h].key = key
  866. data[h].val = val
  867. proc iiTablePut(t: var TIITable, key, val: int) =
  868. var index = iiTableRawGet(t, key)
  869. if index >= 0:
  870. assert(t.data[index].key != InvalidKey)
  871. t.data[index].val = val
  872. else:
  873. if mustRehash(len(t.data), t.counter):
  874. var n: TIIPairSeq
  875. newSeq(n, len(t.data) * GrowthFactor)
  876. for i in countup(0, high(n)): n[i].key = InvalidKey
  877. for i in countup(0, high(t.data)):
  878. if t.data[i].key != InvalidKey:
  879. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  880. swap(t.data, n)
  881. iiTableRawInsert(t.data, key, val)
  882. inc(t.counter)
  883. proc isAddrNode*(n: PNode): bool =
  884. case n.kind
  885. of nkAddr, nkHiddenAddr: true
  886. of nkCallKinds:
  887. if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
  888. else: false
  889. else: false