astalgo.nim 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  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. # these are for debugging only: They are not really deprecated, but I want
  24. # the warning so that release versions do not contain debugging statements:
  25. proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.}
  26. proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
  27. proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
  28. proc typekinds*(t: PType) {.deprecated.} =
  29. var t = t
  30. var s = ""
  31. while t != nil and t.len > 0:
  32. s.add $t.kind
  33. s.add " "
  34. t = t.lastSon
  35. echo s
  36. template debug*(x: PSym|PType|PNode) {.deprecated.} =
  37. when compiles(c.config):
  38. debug(c.config, x)
  39. elif compiles(c.graph.config):
  40. debug(c.graph.config, x)
  41. else:
  42. error()
  43. template debug*(x: auto) {.deprecated.} =
  44. echo x
  45. template mdbg*: bool {.deprecated.} =
  46. when compiles(c.graph):
  47. c.module.fileIdx == c.graph.config.projectMainIdx
  48. elif compiles(c.module):
  49. c.module.fileIdx == c.config.projectMainIdx
  50. elif compiles(c.c.module):
  51. c.c.module.fileIdx == c.c.config.projectMainIdx
  52. elif compiles(m.c.module):
  53. m.c.module.fileIdx == m.c.config.projectMainIdx
  54. elif compiles(cl.c.module):
  55. cl.c.module.fileIdx == cl.c.config.projectMainIdx
  56. elif compiles(p):
  57. when compiles(p.lex):
  58. p.lex.fileIdx == p.lex.config.projectMainIdx
  59. else:
  60. p.module.module.fileIdx == p.config.projectMainIdx
  61. elif compiles(m.module.fileIdx):
  62. m.module.fileIdx == m.config.projectMainIdx
  63. elif compiles(L.fileIdx):
  64. L.fileIdx == L.config.projectMainIdx
  65. else:
  66. error()
  67. # --------------------------- ident tables ----------------------------------
  68. proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
  69. proc idTableGet*(t: TIdTable, key: int): RootRef
  70. proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
  71. proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
  72. # checks if `t` contains the `key` (compared by the pointer value, not only
  73. # `key`'s id)
  74. proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
  75. proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
  76. # ---------------------------------------------------------------------------
  77. proc lookupInRecord*(n: PNode, field: PIdent): PSym
  78. proc mustRehash*(length, counter: int): bool
  79. proc nextTry*(h, maxHash: Hash): Hash {.inline.}
  80. # ------------- table[int, int] ---------------------------------------------
  81. const
  82. InvalidKey* = low(int)
  83. type
  84. TIIPair*{.final.} = object
  85. key*, val*: int
  86. TIIPairSeq* = seq[TIIPair]
  87. TIITable*{.final.} = object # table[int, int]
  88. counter*: int
  89. data*: TIIPairSeq
  90. proc initIiTable*(x: var TIITable)
  91. proc iiTableGet*(t: TIITable, key: int): int
  92. proc iiTablePut*(t: var TIITable, key, val: int)
  93. # implementation
  94. proc skipConvAndClosure*(n: PNode): PNode =
  95. result = n
  96. while true:
  97. case result.kind
  98. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
  99. nkClosure:
  100. result = result[0]
  101. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  102. result = result[1]
  103. else: break
  104. proc sameValue*(a, b: PNode): bool =
  105. result = false
  106. case a.kind
  107. of nkCharLit..nkUInt64Lit:
  108. if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) == getInt(b)
  109. of nkFloatLit..nkFloat64Lit:
  110. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
  111. of nkStrLit..nkTripleStrLit:
  112. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
  113. else:
  114. # don't raise an internal error for 'nim check':
  115. #InternalError(a.info, "SameValue")
  116. discard
  117. proc leValue*(a, b: PNode): bool =
  118. # a <= b?
  119. result = false
  120. case a.kind
  121. of nkCharLit..nkUInt64Lit:
  122. if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) <= getInt(b)
  123. of nkFloatLit..nkFloat64Lit:
  124. if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
  125. of nkStrLit..nkTripleStrLit:
  126. if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
  127. else:
  128. # don't raise an internal error for 'nim check':
  129. #InternalError(a.info, "leValue")
  130. discard
  131. proc weakLeValue*(a, b: PNode): TImplication =
  132. if a.kind notin nkLiterals or b.kind notin nkLiterals:
  133. result = impUnknown
  134. else:
  135. result = if leValue(a, b): impYes else: impNo
  136. proc lookupInRecord(n: PNode, field: PIdent): PSym =
  137. result = nil
  138. case n.kind
  139. of nkRecList:
  140. for i in 0..<n.len:
  141. result = lookupInRecord(n[i], field)
  142. if result != nil: return
  143. of nkRecCase:
  144. if (n[0].kind != nkSym): return nil
  145. result = lookupInRecord(n[0], field)
  146. if result != nil: return
  147. for i in 1..<n.len:
  148. case n[i].kind
  149. of nkOfBranch, nkElse:
  150. result = lookupInRecord(lastSon(n[i]), field)
  151. if result != nil: return
  152. else: return nil
  153. of nkSym:
  154. if n.sym.name.id == field.id: result = n.sym
  155. else: return nil
  156. proc getModule*(s: PSym): PSym =
  157. result = s
  158. assert((result.kind == skModule) or (result.owner != result))
  159. while result != nil and result.kind != skModule: result = result.owner
  160. proc fromSystem*(op: PSym): bool {.inline.} = sfSystemModule in getModule(op).flags
  161. proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
  162. for i in start..<list.len:
  163. if list[i].kind == nkSym:
  164. result = list[i].sym
  165. if result.name.id == ident.id: return
  166. else: return nil
  167. result = nil
  168. proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
  169. if a[0] != b[0]: return false
  170. var alen = a.len - 1
  171. while alen > 0 and a[alen] != '`': dec(alen)
  172. if alen <= 0: alen = a.len
  173. var i = 1
  174. var j = 1
  175. while true:
  176. while i < alen and a[i] == '_': inc i
  177. while j < b.len and b[j] == '_': inc j
  178. var aa = if i < alen: toLowerAscii(a[i]) else: '\0'
  179. var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
  180. if aa != bb: return false
  181. # the characters are identical:
  182. if i >= alen:
  183. # both cursors at the end:
  184. if j >= b.len: return true
  185. # not yet at the end of 'b':
  186. return false
  187. elif j >= b.len:
  188. return false
  189. inc i
  190. inc j
  191. proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
  192. ## Named parameters are special because a named parameter can be
  193. ## gensym'ed and then they have '\`<number>' suffix that we need to
  194. ## ignore, see compiler / evaltempl.nim, snippet:
  195. ##
  196. ##..code-block:: nim
  197. ##
  198. ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
  199. ## if c.instLines: actual.info else: templ.info)
  200. for i in 1..<list.len:
  201. let it = list[i].sym
  202. if it.name.id == ident.id or
  203. sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
  204. proc hashNode(p: RootRef): Hash =
  205. result = hash(cast[pointer](p))
  206. proc mustRehash(length, counter: int): bool =
  207. assert(length > counter)
  208. result = (length * 2 < counter * 3) or (length - counter < 4)
  209. proc rspaces(x: int): Rope =
  210. # returns x spaces
  211. result = rope(spaces(x))
  212. proc toYamlChar(c: char): string =
  213. case c
  214. of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
  215. of '\'', '\"', '\\': result = '\\' & c
  216. else: result = $c
  217. proc makeYamlString*(s: string): Rope =
  218. # We have to split long strings into many ropes. Otherwise
  219. # this could trigger InternalError(111). See the ropes module for
  220. # further information.
  221. const MaxLineLength = 64
  222. result = nil
  223. var res = "\""
  224. for i in 0..<s.len:
  225. if (i + 1) mod MaxLineLength == 0:
  226. res.add('\"')
  227. res.add("\n")
  228. result.add(rope(res))
  229. res = "\"" # reset
  230. res.add(toYamlChar(s[i]))
  231. res.add('\"')
  232. result.add(rope(res))
  233. proc flagsToStr[T](flags: set[T]): Rope =
  234. if flags == {}:
  235. result = rope("[]")
  236. else:
  237. result = nil
  238. for x in items(flags):
  239. if result != nil: result.add(", ")
  240. result.add(makeYamlString($x))
  241. result = "[" & result & "]"
  242. proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
  243. result = "[$1, $2, $3]" % [makeYamlString(toFilename(conf, info)),
  244. rope(toLinenumber(info)),
  245. rope(toColumn(info))]
  246. proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet,
  247. indent, maxRecDepth: int): Rope
  248. proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet,
  249. indent, maxRecDepth: int): Rope
  250. proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet,
  251. indent, maxRecDepth: int): Rope
  252. proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
  253. maxRecDepth: int): Rope =
  254. if n == nil:
  255. result = rope("null")
  256. elif containsOrIncl(marker, n.id):
  257. result = "\"$1\"" % [rope(n.name.s)]
  258. else:
  259. var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
  260. #rope("typ"), typeToYamlAux(conf, n.typ, marker,
  261. # indent + 2, maxRecDepth - 1),
  262. let istr = rspaces(indent + 2)
  263. result = rope("{")
  264. result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
  265. result.addf("$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
  266. result.addf("$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
  267. if conf != nil:
  268. # if we don't pass the config, we probably don't care about the line info
  269. result.addf("$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  270. if card(n.flags) > 0:
  271. result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
  272. result.addf("$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
  273. result.addf("$N$1\"ast\": $2", [istr, ast])
  274. result.addf("$N$1\"options\": $2", [istr, flagsToStr(n.options)])
  275. result.addf("$N$1\"position\": $2", [istr, rope(n.position)])
  276. result.addf("$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
  277. result.addf("$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
  278. if card(n.loc.flags) > 0:
  279. result.addf("$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
  280. result.addf("$N$1\"r\": $2", [istr, n.loc.r])
  281. result.addf("$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
  282. result.addf("$N$1}", [rspaces(indent)])
  283. proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
  284. maxRecDepth: int): Rope =
  285. var sonsRope: Rope
  286. if n == nil:
  287. sonsRope = rope("null")
  288. elif containsOrIncl(marker, n.id):
  289. sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
  290. strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
  291. else:
  292. if n.len > 0:
  293. sonsRope = rope("[")
  294. for i in 0..<n.len:
  295. if i > 0: sonsRope.add(",")
  296. sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n[i],
  297. marker, indent + 4, maxRecDepth - 1)])
  298. sonsRope.addf("$N$1]", [rspaces(indent + 2)])
  299. else:
  300. sonsRope = rope("null")
  301. let istr = rspaces(indent + 2)
  302. result = rope("{")
  303. result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
  304. result.addf("$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
  305. result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
  306. if card(n.flags) > 0:
  307. result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
  308. result.addf("$N$1\"callconv\": $2", [istr, makeYamlString(CallingConvToStr[n.callConv])])
  309. result.addf("$N$1\"size\": $2", [istr, rope(n.size)])
  310. result.addf("$N$1\"align\": $2", [istr, rope(n.align)])
  311. result.addf("$N$1\"sons\": $2", [istr, sonsRope])
  312. proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
  313. maxRecDepth: int): Rope =
  314. if n == nil:
  315. result = rope("null")
  316. else:
  317. var istr = rspaces(indent + 2)
  318. result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
  319. if maxRecDepth != 0:
  320. if conf != nil:
  321. result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
  322. case n.kind
  323. of nkCharLit..nkInt64Lit:
  324. result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
  325. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  326. result.addf(",$N$1\"floatVal\": $2",
  327. [istr, rope(n.floatVal.toStrMaxPrecision)])
  328. of nkStrLit..nkTripleStrLit:
  329. result.addf(",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
  330. of nkSym:
  331. result.addf(",$N$1\"sym\": $2",
  332. [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
  333. of nkIdent:
  334. if n.ident != nil:
  335. result.addf(",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
  336. else:
  337. result.addf(",$N$1\"ident\": null", [istr])
  338. else:
  339. if n.len > 0:
  340. result.addf(",$N$1\"sons\": [", [istr])
  341. for i in 0..<n.len:
  342. if i > 0: result.add(",")
  343. result.addf("$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n[i],
  344. marker, indent + 4, maxRecDepth - 1)])
  345. result.addf("$N$1]", [istr])
  346. result.addf(",$N$1\"typ\": $2",
  347. [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
  348. result.addf("$N$1}", [rspaces(indent)])
  349. proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
  350. var marker = initIntSet()
  351. result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
  352. proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
  353. var marker = initIntSet()
  354. result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
  355. proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
  356. var marker = initIntSet()
  357. result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
  358. import tables
  359. const backrefStyle = "\e[90m"
  360. const enumStyle = "\e[34m"
  361. const numberStyle = "\e[33m"
  362. const stringStyle = "\e[32m"
  363. const resetStyle = "\e[0m"
  364. type
  365. DebugPrinter = object
  366. conf: ConfigRef
  367. visited: Table[pointer, int]
  368. renderSymType: bool
  369. indent: int
  370. currentLine: int
  371. firstItem: bool
  372. useColor: bool
  373. res: string
  374. proc indentMore(this: var DebugPrinter) =
  375. this.indent += 2
  376. proc indentLess(this: var DebugPrinter) =
  377. this.indent -= 2
  378. proc newlineAndIndent(this: var DebugPrinter) =
  379. this.res.add "\n"
  380. this.currentLine += 1
  381. for i in 0..<this.indent:
  382. this.res.add ' '
  383. proc openCurly(this: var DebugPrinter) =
  384. this.res.add "{"
  385. this.indentMore
  386. this.firstItem = true
  387. proc closeCurly(this: var DebugPrinter) =
  388. this.indentLess
  389. this.newlineAndIndent
  390. this.res.add "}"
  391. proc comma(this: var DebugPrinter) =
  392. this.res.add ", "
  393. proc openBracket(this: var DebugPrinter) =
  394. this.res.add "["
  395. #this.indentMore
  396. proc closeBracket(this: var DebugPrinter) =
  397. #this.indentLess
  398. this.res.add "]"
  399. proc key(this: var DebugPrinter; key: string) =
  400. if not this.firstItem:
  401. this.res.add ","
  402. this.firstItem = false
  403. this.newlineAndIndent
  404. this.res.add "\""
  405. this.res.add key
  406. this.res.add "\": "
  407. proc value(this: var DebugPrinter; value: string) =
  408. if this.useColor:
  409. this.res.add stringStyle
  410. this.res.add "\""
  411. this.res.add value
  412. this.res.add "\""
  413. if this.useColor:
  414. this.res.add resetStyle
  415. proc value(this: var DebugPrinter; value: BiggestInt) =
  416. if this.useColor:
  417. this.res.add numberStyle
  418. this.res.addInt value
  419. if this.useColor:
  420. this.res.add resetStyle
  421. proc value[T: enum](this: var DebugPrinter; value: T) =
  422. if this.useColor:
  423. this.res.add enumStyle
  424. this.res.add "\""
  425. this.res.add $value
  426. this.res.add "\""
  427. if this.useColor:
  428. this.res.add resetStyle
  429. proc value[T: enum](this: var DebugPrinter; value: set[T]) =
  430. this.openBracket
  431. let high = card(value)-1
  432. var i = 0
  433. for v in value:
  434. this.value v
  435. if i != high:
  436. this.comma
  437. inc i
  438. this.closeBracket
  439. template earlyExit(this: var DebugPrinter; n: PType | PNode | PSym) =
  440. if n == nil:
  441. this.res.add "null"
  442. return
  443. let index = this.visited.getOrDefault(cast[pointer](n), -1)
  444. if index < 0:
  445. this.visited[cast[pointer](n)] = this.currentLine
  446. else:
  447. if this.useColor:
  448. this.res.add backrefStyle
  449. this.res.add "<defined "
  450. this.res.addInt(this.currentLine - index)
  451. this.res.add " lines upwards>"
  452. if this.useColor:
  453. this.res.add resetStyle
  454. return
  455. proc value(this: var DebugPrinter; value: PType)
  456. proc value(this: var DebugPrinter; value: PNode)
  457. proc value(this: var DebugPrinter; value: PSym) =
  458. earlyExit(this, value)
  459. this.openCurly
  460. this.key("kind")
  461. this.value(value.kind)
  462. this.key("name")
  463. this.value(value.name.s)
  464. this.key("id")
  465. this.value(value.id)
  466. if value.kind in {skField, skEnumField, skParam}:
  467. this.key("position")
  468. this.value(value.position)
  469. if card(value.flags) > 0:
  470. this.key("flags")
  471. this.value(value.flags)
  472. if this.renderSymType and value.typ != nil:
  473. this.key "typ"
  474. this.value(value.typ)
  475. this.closeCurly
  476. proc value(this: var DebugPrinter; value: PType) =
  477. earlyExit(this, value)
  478. this.openCurly
  479. this.key "kind"
  480. this.value value.kind
  481. this.key "id"
  482. this.value value.id
  483. if value.sym != nil:
  484. this.key "sym"
  485. this.value value.sym
  486. #this.value value.sym.name.s
  487. if card(value.flags) > 0:
  488. this.key "flags"
  489. this.value value.flags
  490. if value.kind in IntegralTypes and value.n != nil:
  491. this.key "n"
  492. this.value value.n
  493. if value.len > 0:
  494. this.key "sons"
  495. this.openBracket
  496. for i in 0..<value.len:
  497. this.value value[i]
  498. if i != value.len - 1:
  499. this.comma
  500. this.closeBracket
  501. if value.n != nil:
  502. this.key "n"
  503. this.value value.n
  504. this.closeCurly
  505. proc value(this: var DebugPrinter; value: PNode) =
  506. earlyExit(this, value)
  507. this.openCurly
  508. this.key "kind"
  509. this.value value.kind
  510. when defined(useNodeIds):
  511. this.key "id"
  512. this.value value.id
  513. if this.conf != nil:
  514. this.key "info"
  515. this.value $lineInfoToStr(this.conf, value.info)
  516. if card(value.flags) > 0:
  517. this.key "flags"
  518. this.value value.flags
  519. case value.kind
  520. of nkCharLit..nkUInt64Lit:
  521. this.key "intVal"
  522. this.value value.intVal
  523. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  524. this.key "floatVal"
  525. this.value value.floatVal.toStrMaxPrecision
  526. of nkStrLit..nkTripleStrLit:
  527. this.key "strVal"
  528. this.value value.strVal
  529. of nkSym:
  530. this.key "sym"
  531. this.value value.sym
  532. #this.value value.sym.name.s
  533. of nkIdent:
  534. if value.ident != nil:
  535. this.key "ident"
  536. this.value value.ident.s
  537. else:
  538. if this.renderSymType and value.typ != nil:
  539. this.key "typ"
  540. this.value value.typ
  541. if value.len > 0:
  542. this.key "sons"
  543. this.openBracket
  544. for i in 0..<value.len:
  545. this.value value[i]
  546. if i != value.len - 1:
  547. this.comma
  548. this.closeBracket
  549. this.closeCurly
  550. proc debug(n: PSym; conf: ConfigRef) =
  551. var this: DebugPrinter
  552. this.visited = initTable[pointer, int]()
  553. this.renderSymType = true
  554. this.useColor = not defined(windows)
  555. this.value(n)
  556. echo($this.res)
  557. proc debug(n: PType; conf: ConfigRef) =
  558. var this: DebugPrinter
  559. this.visited = initTable[pointer, int]()
  560. this.renderSymType = true
  561. this.useColor = not defined(windows)
  562. this.value(n)
  563. echo($this.res)
  564. proc debug(n: PNode; conf: ConfigRef) =
  565. var this: DebugPrinter
  566. this.visited = initTable[pointer, int]()
  567. #this.renderSymType = true
  568. this.useColor = not defined(windows)
  569. this.value(n)
  570. echo($this.res)
  571. proc nextTry(h, maxHash: Hash): Hash =
  572. result = ((5 * h) + 1) and maxHash
  573. # For any initial h in range(maxHash), repeating that maxHash times
  574. # generates each int in range(maxHash) exactly once (see any text on
  575. # random-number generation for proof).
  576. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
  577. # returns true whether n is in t
  578. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  579. while t.data[h] != nil:
  580. if t.data[h] == obj:
  581. return true
  582. h = nextTry(h, high(t.data))
  583. result = false
  584. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  585. var h: Hash = hashNode(obj) and high(data)
  586. while data[h] != nil:
  587. assert(data[h] != obj)
  588. h = nextTry(h, high(data))
  589. assert(data[h] == nil)
  590. data[h] = obj
  591. proc objectSetEnlarge(t: var TObjectSet) =
  592. var n: TObjectSeq
  593. newSeq(n, t.data.len * GrowthFactor)
  594. for i in 0..high(t.data):
  595. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  596. swap(t.data, n)
  597. proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
  598. if mustRehash(t.data.len, t.counter): objectSetEnlarge(t)
  599. objectSetRawInsert(t.data, obj)
  600. inc(t.counter)
  601. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
  602. # returns true if obj is already in the string table:
  603. var h: Hash = hashNode(obj) and high(t.data)
  604. while true:
  605. var it = t.data[h]
  606. if it == nil: break
  607. if it == obj:
  608. return true # found it
  609. h = nextTry(h, high(t.data))
  610. if mustRehash(t.data.len, t.counter):
  611. objectSetEnlarge(t)
  612. objectSetRawInsert(t.data, obj)
  613. else:
  614. assert(t.data[h] == nil)
  615. t.data[h] = obj
  616. inc(t.counter)
  617. result = false
  618. proc strTableContains*(t: TStrTable, n: PSym): bool =
  619. var h: Hash = n.name.h and high(t.data) # start with real hash value
  620. while t.data[h] != nil:
  621. if (t.data[h] == n):
  622. return true
  623. h = nextTry(h, high(t.data))
  624. result = false
  625. proc strTableRawInsert(data: var seq[PSym], n: PSym) =
  626. var h: Hash = n.name.h and high(data)
  627. while data[h] != nil:
  628. if data[h] == n:
  629. # allowed for 'export' feature:
  630. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  631. return
  632. h = nextTry(h, high(data))
  633. assert(data[h] == nil)
  634. data[h] = n
  635. proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
  636. assert prevSym.name.h == newSym.name.h
  637. var h: Hash = prevSym.name.h and high(data)
  638. while data[h] != nil:
  639. if data[h] == prevSym:
  640. data[h] = newSym
  641. return
  642. h = nextTry(h, high(data))
  643. assert false
  644. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  645. symTabReplaceRaw(t.data, prevSym, newSym)
  646. proc strTableEnlarge(t: var TStrTable) =
  647. var n: seq[PSym]
  648. newSeq(n, t.data.len * GrowthFactor)
  649. for i in 0..high(t.data):
  650. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  651. swap(t.data, n)
  652. proc strTableAdd*(t: var TStrTable, n: PSym) =
  653. if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
  654. strTableRawInsert(t.data, n)
  655. inc(t.counter)
  656. proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
  657. onConflictKeepOld = false): PSym =
  658. # returns true if n is already in the string table:
  659. # It is essential that `n` is written nevertheless!
  660. # This way the newest redefinition is picked by the semantic analyses!
  661. assert n.name != nil
  662. var h: Hash = n.name.h and high(t.data)
  663. var replaceSlot = -1
  664. while true:
  665. var it = t.data[h]
  666. if it == nil: break
  667. # Semantic checking can happen multiple times thanks to templates
  668. # and overloading: (var x=@[]; x).mapIt(it).
  669. # So it is possible the very same sym is added multiple
  670. # times to the symbol table which we allow here with the 'it == n' check.
  671. if it.name.id == n.name.id:
  672. if it == n: return nil
  673. replaceSlot = h
  674. h = nextTry(h, high(t.data))
  675. if replaceSlot >= 0:
  676. if not onConflictKeepOld:
  677. t.data[replaceSlot] = n # overwrite it with newer definition!
  678. return t.data[replaceSlot] # found it
  679. elif mustRehash(t.data.len, t.counter):
  680. strTableEnlarge(t)
  681. strTableRawInsert(t.data, n)
  682. else:
  683. assert(t.data[h] == nil)
  684. t.data[h] = n
  685. inc(t.counter)
  686. result = nil
  687. proc strTableIncl*(t: var TStrTable, n: PSym;
  688. onConflictKeepOld = false): bool {.discardable.} =
  689. result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
  690. proc strTableGet*(t: TStrTable, name: PIdent): PSym =
  691. var h: Hash = name.h and high(t.data)
  692. while true:
  693. result = t.data[h]
  694. if result == nil: break
  695. if result.name.id == name.id: break
  696. h = nextTry(h, high(t.data))
  697. type
  698. TIdentIter* = object # iterator over all syms with same identifier
  699. h*: Hash # current hash
  700. name*: PIdent
  701. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
  702. var h = ti.h and high(tab.data)
  703. var start = h
  704. result = tab.data[h]
  705. while result != nil:
  706. if result.name.id == ti.name.id: break
  707. h = nextTry(h, high(tab.data))
  708. if h == start:
  709. result = nil
  710. break
  711. result = tab.data[h]
  712. ti.h = nextTry(h, high(tab.data))
  713. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  714. ti.h = s.h
  715. ti.name = s
  716. if tab.counter == 0: result = nil
  717. else: result = nextIdentIter(ti, tab)
  718. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  719. excluding: IntSet): PSym =
  720. var h: Hash = ti.h and high(tab.data)
  721. var start = h
  722. result = tab.data[h]
  723. while result != nil:
  724. if result.name.id == ti.name.id and not contains(excluding, result.id):
  725. break
  726. h = nextTry(h, high(tab.data))
  727. if h == start:
  728. result = nil
  729. break
  730. result = tab.data[h]
  731. ti.h = nextTry(h, high(tab.data))
  732. if result != nil and contains(excluding, result.id): result = nil
  733. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  734. excluding: IntSet): PSym =
  735. ti.h = s.h
  736. ti.name = s
  737. if tab.counter == 0: result = nil
  738. else: result = nextIdentExcluding(ti, tab, excluding)
  739. type
  740. TTabIter* = object
  741. h: Hash
  742. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
  743. # usage:
  744. # var
  745. # i: TTabIter
  746. # s: PSym
  747. # s = InitTabIter(i, table)
  748. # while s != nil:
  749. # ...
  750. # s = NextIter(i, table)
  751. #
  752. result = nil
  753. while (ti.h <= high(tab.data)):
  754. result = tab.data[ti.h]
  755. inc(ti.h) # ... and increment by one always
  756. if result != nil: break
  757. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
  758. ti.h = 0
  759. if tab.counter == 0:
  760. result = nil
  761. else:
  762. result = nextIter(ti, tab)
  763. iterator items*(tab: TStrTable): PSym =
  764. var it: TTabIter
  765. var s = initTabIter(it, tab)
  766. while s != nil:
  767. yield s
  768. s = nextIter(it, tab)
  769. proc hasEmptySlot(data: TIdPairSeq): bool =
  770. for h in 0..high(data):
  771. if data[h].key == nil:
  772. return true
  773. result = false
  774. proc idTableRawGet(t: TIdTable, key: int): int =
  775. var h: Hash
  776. h = key and high(t.data) # start with real hash value
  777. while t.data[h].key != nil:
  778. if t.data[h].key.id == key:
  779. return h
  780. h = nextTry(h, high(t.data))
  781. result = - 1
  782. proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
  783. var index = idTableRawGet(t, key.id)
  784. if index >= 0: result = t.data[index].key == key
  785. else: result = false
  786. proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
  787. var index = idTableRawGet(t, key.id)
  788. if index >= 0: result = t.data[index].val
  789. else: result = nil
  790. proc idTableGet(t: TIdTable, key: int): RootRef =
  791. var index = idTableRawGet(t, key)
  792. if index >= 0: result = t.data[index].val
  793. else: result = nil
  794. iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
  795. for i in 0..high(t.data):
  796. if t.data[i].key != nil:
  797. yield (t.data[i].key.id, t.data[i].val)
  798. proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
  799. var h: Hash
  800. h = key.id and high(data)
  801. while data[h].key != nil:
  802. assert(data[h].key.id != key.id)
  803. h = nextTry(h, high(data))
  804. assert(data[h].key == nil)
  805. data[h].key = key
  806. data[h].val = val
  807. proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
  808. var
  809. index: int
  810. n: TIdPairSeq
  811. index = idTableRawGet(t, key.id)
  812. if index >= 0:
  813. assert(t.data[index].key != nil)
  814. t.data[index].val = val
  815. else:
  816. if mustRehash(t.data.len, t.counter):
  817. newSeq(n, t.data.len * GrowthFactor)
  818. for i in 0..high(t.data):
  819. if t.data[i].key != nil:
  820. idTableRawInsert(n, t.data[i].key, t.data[i].val)
  821. assert(hasEmptySlot(n))
  822. swap(t.data, n)
  823. idTableRawInsert(t.data, key, val)
  824. inc(t.counter)
  825. iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
  826. for i in 0..high(t.data):
  827. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  828. proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
  829. var h: Hash
  830. h = key.id and high(t.data) # start with real hash value
  831. while t.data[h].key != nil:
  832. if t.data[h].key.id == key.id:
  833. return h
  834. h = nextTry(h, high(t.data))
  835. result = - 1
  836. proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
  837. var index: int
  838. index = idNodeTableRawGet(t, key)
  839. if index >= 0: result = t.data[index].val
  840. else: result = nil
  841. proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
  842. var h: Hash
  843. h = key.id and high(data)
  844. while data[h].key != nil:
  845. assert(data[h].key.id != key.id)
  846. h = nextTry(h, high(data))
  847. assert(data[h].key == nil)
  848. data[h].key = key
  849. data[h].val = val
  850. proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  851. var index = idNodeTableRawGet(t, key)
  852. if index >= 0:
  853. assert(t.data[index].key != nil)
  854. t.data[index].val = val
  855. else:
  856. if mustRehash(t.data.len, t.counter):
  857. var n: TIdNodePairSeq
  858. newSeq(n, t.data.len * GrowthFactor)
  859. for i in 0..high(t.data):
  860. if t.data[i].key != nil:
  861. idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
  862. swap(t.data, n)
  863. idNodeTableRawInsert(t.data, key, val)
  864. inc(t.counter)
  865. iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
  866. for i in 0..high(t.data):
  867. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  868. proc initIITable(x: var TIITable) =
  869. x.counter = 0
  870. newSeq(x.data, StartSize)
  871. for i in 0..<StartSize: x.data[i].key = InvalidKey
  872. proc iiTableRawGet(t: TIITable, key: int): int =
  873. var h: Hash
  874. h = key and high(t.data) # start with real hash value
  875. while t.data[h].key != InvalidKey:
  876. if t.data[h].key == key: return h
  877. h = nextTry(h, high(t.data))
  878. result = -1
  879. proc iiTableGet(t: TIITable, key: int): int =
  880. var index = iiTableRawGet(t, key)
  881. if index >= 0: result = t.data[index].val
  882. else: result = InvalidKey
  883. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  884. var h: Hash
  885. h = key and high(data)
  886. while data[h].key != InvalidKey:
  887. assert(data[h].key != key)
  888. h = nextTry(h, high(data))
  889. assert(data[h].key == InvalidKey)
  890. data[h].key = key
  891. data[h].val = val
  892. proc iiTablePut(t: var TIITable, key, val: int) =
  893. var index = iiTableRawGet(t, key)
  894. if index >= 0:
  895. assert(t.data[index].key != InvalidKey)
  896. t.data[index].val = val
  897. else:
  898. if mustRehash(t.data.len, t.counter):
  899. var n: TIIPairSeq
  900. newSeq(n, t.data.len * GrowthFactor)
  901. for i in 0..high(n): n[i].key = InvalidKey
  902. for i in 0..high(t.data):
  903. if t.data[i].key != InvalidKey:
  904. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  905. swap(t.data, n)
  906. iiTableRawInsert(t.data, key, val)
  907. inc(t.counter)
  908. proc isAddrNode*(n: PNode): bool =
  909. case n.kind
  910. of nkAddr, nkHiddenAddr: true
  911. of nkCallKinds:
  912. if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
  913. else: false
  914. else: false
  915. proc listSymbolNames*(symbols: openArray[PSym]): string =
  916. for sym in symbols:
  917. if result.len > 0:
  918. result.add ", "
  919. result.add sym.name.s
  920. proc isDiscriminantField*(n: PNode): bool =
  921. if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags
  922. elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags
  923. else: false