astalgo.nim 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  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 skipConvCastAndClosure*(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, nkCast:
  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($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. if value.comment.len > 0:
  511. this.key "comment"
  512. this.value value.comment
  513. when defined(useNodeIds):
  514. this.key "id"
  515. this.value value.id
  516. if this.conf != nil:
  517. this.key "info"
  518. this.value $lineInfoToStr(this.conf, value.info)
  519. if value.flags != {}:
  520. this.key "flags"
  521. this.value value.flags
  522. if value.typ != nil:
  523. this.key "typ"
  524. this.value value.typ.kind
  525. else:
  526. this.key "typ"
  527. this.value "nil"
  528. case value.kind
  529. of nkCharLit..nkUInt64Lit:
  530. this.key "intVal"
  531. this.value value.intVal
  532. of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
  533. this.key "floatVal"
  534. this.value value.floatVal.toStrMaxPrecision
  535. of nkStrLit..nkTripleStrLit:
  536. this.key "strVal"
  537. this.value value.strVal
  538. of nkSym:
  539. this.key "sym"
  540. this.value value.sym
  541. #this.value value.sym.name.s
  542. of nkIdent:
  543. if value.ident != nil:
  544. this.key "ident"
  545. this.value value.ident.s
  546. else:
  547. if this.renderSymType and value.typ != nil:
  548. this.key "typ"
  549. this.value value.typ
  550. if value.len > 0:
  551. this.key "sons"
  552. this.openBracket
  553. for i in 0..<value.len:
  554. this.value value[i]
  555. if i != value.len - 1:
  556. this.comma
  557. this.closeBracket
  558. this.closeCurly
  559. proc debug(n: PSym; conf: ConfigRef) =
  560. var this: DebugPrinter
  561. this.visited = initTable[pointer, int]()
  562. this.renderSymType = true
  563. this.useColor = not defined(windows)
  564. this.value(n)
  565. echo($this.res)
  566. proc debug(n: PType; conf: ConfigRef) =
  567. var this: DebugPrinter
  568. this.visited = initTable[pointer, int]()
  569. this.renderSymType = true
  570. this.useColor = not defined(windows)
  571. this.value(n)
  572. echo($this.res)
  573. proc debug(n: PNode; conf: ConfigRef) =
  574. var this: DebugPrinter
  575. this.visited = initTable[pointer, int]()
  576. #this.renderSymType = true
  577. this.useColor = not defined(windows)
  578. this.value(n)
  579. echo($this.res)
  580. proc nextTry(h, maxHash: Hash): Hash =
  581. result = ((5 * h) + 1) and maxHash
  582. # For any initial h in range(maxHash), repeating that maxHash times
  583. # generates each int in range(maxHash) exactly once (see any text on
  584. # random-number generation for proof).
  585. proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
  586. # returns true whether n is in t
  587. var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
  588. while t.data[h] != nil:
  589. if t.data[h] == obj:
  590. return true
  591. h = nextTry(h, high(t.data))
  592. result = false
  593. proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
  594. var h: Hash = hashNode(obj) and high(data)
  595. while data[h] != nil:
  596. assert(data[h] != obj)
  597. h = nextTry(h, high(data))
  598. assert(data[h] == nil)
  599. data[h] = obj
  600. proc objectSetEnlarge(t: var TObjectSet) =
  601. var n: TObjectSeq
  602. newSeq(n, t.data.len * GrowthFactor)
  603. for i in 0..high(t.data):
  604. if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
  605. swap(t.data, n)
  606. proc objectSetIncl*(t: var TObjectSet, obj: RootRef) =
  607. if mustRehash(t.data.len, t.counter): objectSetEnlarge(t)
  608. objectSetRawInsert(t.data, obj)
  609. inc(t.counter)
  610. proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
  611. # returns true if obj is already in the string table:
  612. var h: Hash = hashNode(obj) and high(t.data)
  613. while true:
  614. var it = t.data[h]
  615. if it == nil: break
  616. if it == obj:
  617. return true # found it
  618. h = nextTry(h, high(t.data))
  619. if mustRehash(t.data.len, t.counter):
  620. objectSetEnlarge(t)
  621. objectSetRawInsert(t.data, obj)
  622. else:
  623. assert(t.data[h] == nil)
  624. t.data[h] = obj
  625. inc(t.counter)
  626. result = false
  627. proc strTableContains*(t: TStrTable, n: PSym): bool =
  628. var h: Hash = n.name.h and high(t.data) # start with real hash value
  629. while t.data[h] != nil:
  630. if (t.data[h] == n):
  631. return true
  632. h = nextTry(h, high(t.data))
  633. result = false
  634. proc strTableRawInsert(data: var seq[PSym], n: PSym) =
  635. var h: Hash = n.name.h and high(data)
  636. while data[h] != nil:
  637. if data[h] == n:
  638. # allowed for 'export' feature:
  639. #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
  640. return
  641. h = nextTry(h, high(data))
  642. assert(data[h] == nil)
  643. data[h] = n
  644. proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
  645. assert prevSym.name.h == newSym.name.h
  646. var h: Hash = prevSym.name.h and high(data)
  647. while data[h] != nil:
  648. if data[h] == prevSym:
  649. data[h] = newSym
  650. return
  651. h = nextTry(h, high(data))
  652. assert false
  653. proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
  654. symTabReplaceRaw(t.data, prevSym, newSym)
  655. proc strTableEnlarge(t: var TStrTable) =
  656. var n: seq[PSym]
  657. newSeq(n, t.data.len * GrowthFactor)
  658. for i in 0..high(t.data):
  659. if t.data[i] != nil: strTableRawInsert(n, t.data[i])
  660. swap(t.data, n)
  661. proc strTableAdd*(t: var TStrTable, n: PSym) =
  662. if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
  663. strTableRawInsert(t.data, n)
  664. inc(t.counter)
  665. proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
  666. onConflictKeepOld = false): PSym =
  667. # if `t` has a conflicting symbol (same identifier as `n`), return it
  668. # otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true`
  669. # and a conflict was found.
  670. assert n.name != nil
  671. var h: Hash = n.name.h and high(t.data)
  672. var replaceSlot = -1
  673. while true:
  674. var it = t.data[h]
  675. if it == nil: break
  676. # Semantic checking can happen multiple times thanks to templates
  677. # and overloading: (var x=@[]; x).mapIt(it).
  678. # So it is possible the very same sym is added multiple
  679. # times to the symbol table which we allow here with the 'it == n' check.
  680. if it.name.id == n.name.id:
  681. if it == n: return nil
  682. replaceSlot = h
  683. h = nextTry(h, high(t.data))
  684. if replaceSlot >= 0:
  685. result = t.data[replaceSlot] # found it
  686. if not onConflictKeepOld:
  687. t.data[replaceSlot] = n # overwrite it with newer definition!
  688. return result # but return the old one
  689. elif mustRehash(t.data.len, t.counter):
  690. strTableEnlarge(t)
  691. strTableRawInsert(t.data, n)
  692. else:
  693. assert(t.data[h] == nil)
  694. t.data[h] = n
  695. inc(t.counter)
  696. result = nil
  697. proc strTableIncl*(t: var TStrTable, n: PSym;
  698. onConflictKeepOld = false): bool {.discardable.} =
  699. result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
  700. proc strTableGet*(t: TStrTable, name: PIdent): PSym =
  701. var h: Hash = name.h and high(t.data)
  702. while true:
  703. result = t.data[h]
  704. if result == nil: break
  705. if result.name.id == name.id: break
  706. h = nextTry(h, high(t.data))
  707. type
  708. TIdentIter* = object # iterator over all syms with same identifier
  709. h*: Hash # current hash
  710. name*: PIdent
  711. proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym =
  712. var h = ti.h and high(tab.data)
  713. var start = h
  714. result = tab.data[h]
  715. while result != nil:
  716. if result.name.id == ti.name.id: break
  717. h = nextTry(h, high(tab.data))
  718. if h == start:
  719. result = nil
  720. break
  721. result = tab.data[h]
  722. ti.h = nextTry(h, high(tab.data))
  723. proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
  724. ti.h = s.h
  725. ti.name = s
  726. if tab.counter == 0: result = nil
  727. else: result = nextIdentIter(ti, tab)
  728. proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
  729. excluding: IntSet): PSym =
  730. var h: Hash = ti.h and high(tab.data)
  731. var start = h
  732. result = tab.data[h]
  733. while result != nil:
  734. if result.name.id == ti.name.id and not contains(excluding, result.id):
  735. break
  736. h = nextTry(h, high(tab.data))
  737. if h == start:
  738. result = nil
  739. break
  740. result = tab.data[h]
  741. ti.h = nextTry(h, high(tab.data))
  742. if result != nil and contains(excluding, result.id): result = nil
  743. proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
  744. excluding: IntSet): PSym =
  745. ti.h = s.h
  746. ti.name = s
  747. if tab.counter == 0: result = nil
  748. else: result = nextIdentExcluding(ti, tab, excluding)
  749. type
  750. TTabIter* = object
  751. h: Hash
  752. proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym =
  753. # usage:
  754. # var
  755. # i: TTabIter
  756. # s: PSym
  757. # s = InitTabIter(i, table)
  758. # while s != nil:
  759. # ...
  760. # s = NextIter(i, table)
  761. #
  762. result = nil
  763. while (ti.h <= high(tab.data)):
  764. result = tab.data[ti.h]
  765. inc(ti.h) # ... and increment by one always
  766. if result != nil: break
  767. proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
  768. ti.h = 0
  769. if tab.counter == 0:
  770. result = nil
  771. else:
  772. result = nextIter(ti, tab)
  773. iterator items*(tab: TStrTable): PSym =
  774. var it: TTabIter
  775. var s = initTabIter(it, tab)
  776. while s != nil:
  777. yield s
  778. s = nextIter(it, tab)
  779. proc hasEmptySlot(data: TIdPairSeq): bool =
  780. for h in 0..high(data):
  781. if data[h].key == nil:
  782. return true
  783. result = false
  784. proc idTableRawGet(t: TIdTable, key: int): int =
  785. var h: Hash
  786. h = key and high(t.data) # start with real hash value
  787. while t.data[h].key != nil:
  788. if t.data[h].key.id == key:
  789. return h
  790. h = nextTry(h, high(t.data))
  791. result = - 1
  792. proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
  793. var index = idTableRawGet(t, key.id)
  794. if index >= 0: result = t.data[index].key == key
  795. else: result = false
  796. proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
  797. var index = idTableRawGet(t, key.id)
  798. if index >= 0: result = t.data[index].val
  799. else: result = nil
  800. proc idTableGet(t: TIdTable, key: int): RootRef =
  801. var index = idTableRawGet(t, key)
  802. if index >= 0: result = t.data[index].val
  803. else: result = nil
  804. iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
  805. for i in 0..high(t.data):
  806. if t.data[i].key != nil:
  807. yield (t.data[i].key.id, t.data[i].val)
  808. proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
  809. var h: Hash
  810. h = key.id and high(data)
  811. while data[h].key != nil:
  812. assert(data[h].key.id != key.id)
  813. h = nextTry(h, high(data))
  814. assert(data[h].key == nil)
  815. data[h].key = key
  816. data[h].val = val
  817. proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
  818. var
  819. index: int
  820. n: TIdPairSeq
  821. index = idTableRawGet(t, key.id)
  822. if index >= 0:
  823. assert(t.data[index].key != nil)
  824. t.data[index].val = val
  825. else:
  826. if mustRehash(t.data.len, t.counter):
  827. newSeq(n, t.data.len * GrowthFactor)
  828. for i in 0..high(t.data):
  829. if t.data[i].key != nil:
  830. idTableRawInsert(n, t.data[i].key, t.data[i].val)
  831. assert(hasEmptySlot(n))
  832. swap(t.data, n)
  833. idTableRawInsert(t.data, key, val)
  834. inc(t.counter)
  835. iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
  836. for i in 0..high(t.data):
  837. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  838. proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
  839. var h: Hash
  840. h = key.id and high(t.data) # start with real hash value
  841. while t.data[h].key != nil:
  842. if t.data[h].key.id == key.id:
  843. return h
  844. h = nextTry(h, high(t.data))
  845. result = - 1
  846. proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
  847. var index: int
  848. index = idNodeTableRawGet(t, key)
  849. if index >= 0: result = t.data[index].val
  850. else: result = nil
  851. proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
  852. var h: Hash
  853. h = key.id and high(data)
  854. while data[h].key != nil:
  855. assert(data[h].key.id != key.id)
  856. h = nextTry(h, high(data))
  857. assert(data[h].key == nil)
  858. data[h].key = key
  859. data[h].val = val
  860. proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
  861. var index = idNodeTableRawGet(t, key)
  862. if index >= 0:
  863. assert(t.data[index].key != nil)
  864. t.data[index].val = val
  865. else:
  866. if mustRehash(t.data.len, t.counter):
  867. var n: TIdNodePairSeq
  868. newSeq(n, t.data.len * GrowthFactor)
  869. for i in 0..high(t.data):
  870. if t.data[i].key != nil:
  871. idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
  872. swap(t.data, n)
  873. idNodeTableRawInsert(t.data, key, val)
  874. inc(t.counter)
  875. iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
  876. for i in 0..high(t.data):
  877. if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
  878. proc initIITable(x: var TIITable) =
  879. x.counter = 0
  880. newSeq(x.data, StartSize)
  881. for i in 0..<StartSize: x.data[i].key = InvalidKey
  882. proc iiTableRawGet(t: TIITable, key: int): int =
  883. var h: Hash
  884. h = key and high(t.data) # start with real hash value
  885. while t.data[h].key != InvalidKey:
  886. if t.data[h].key == key: return h
  887. h = nextTry(h, high(t.data))
  888. result = -1
  889. proc iiTableGet(t: TIITable, key: int): int =
  890. var index = iiTableRawGet(t, key)
  891. if index >= 0: result = t.data[index].val
  892. else: result = InvalidKey
  893. proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
  894. var h: Hash
  895. h = key and high(data)
  896. while data[h].key != InvalidKey:
  897. assert(data[h].key != key)
  898. h = nextTry(h, high(data))
  899. assert(data[h].key == InvalidKey)
  900. data[h].key = key
  901. data[h].val = val
  902. proc iiTablePut(t: var TIITable, key, val: int) =
  903. var index = iiTableRawGet(t, key)
  904. if index >= 0:
  905. assert(t.data[index].key != InvalidKey)
  906. t.data[index].val = val
  907. else:
  908. if mustRehash(t.data.len, t.counter):
  909. var n: TIIPairSeq
  910. newSeq(n, t.data.len * GrowthFactor)
  911. for i in 0..high(n): n[i].key = InvalidKey
  912. for i in 0..high(t.data):
  913. if t.data[i].key != InvalidKey:
  914. iiTableRawInsert(n, t.data[i].key, t.data[i].val)
  915. swap(t.data, n)
  916. iiTableRawInsert(t.data, key, val)
  917. inc(t.counter)
  918. proc isAddrNode*(n: PNode): bool =
  919. case n.kind
  920. of nkAddr, nkHiddenAddr: true
  921. of nkCallKinds:
  922. if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
  923. else: false
  924. else: false
  925. proc listSymbolNames*(symbols: openArray[PSym]): string =
  926. for sym in symbols:
  927. if result.len > 0:
  928. result.add ", "
  929. result.add sym.name.s
  930. proc isDiscriminantField*(n: PNode): bool =
  931. if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags
  932. elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags
  933. else: false