astalgo.nim 32 KB

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