packed_ast.nim 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2020 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Packed AST representation, mostly based on a seq of nodes.
  10. ## For IC support. Far future: Rewrite the compiler passes to
  11. ## use this representation directly in all the transformations,
  12. ## it is superior.
  13. import hashes, tables, strtabs
  14. import bitabs
  15. import ".." / [ast, options]
  16. when defined(nimPreviewSlimSystem):
  17. import std/assertions
  18. type
  19. SymId* = distinct int32
  20. ModuleId* = distinct int32
  21. NodePos* = distinct int
  22. NodeId* = distinct int32
  23. PackedItemId* = object
  24. module*: LitId # 0 if it's this module
  25. item*: int32 # same as the in-memory representation
  26. const
  27. nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
  28. const
  29. emptyNodeId* = NodeId(-1)
  30. type
  31. PackedLineInfo* = object
  32. line*: uint16
  33. col*: int16
  34. file*: LitId
  35. PackedLib* = object
  36. kind*: TLibKind
  37. generated*: bool
  38. isOverriden*: bool
  39. name*: LitId
  40. path*: NodeId
  41. PackedSym* = object
  42. kind*: TSymKind
  43. name*: LitId
  44. typ*: PackedItemId
  45. flags*: TSymFlags
  46. magic*: TMagic
  47. info*: PackedLineInfo
  48. ast*: NodeId
  49. owner*: PackedItemId
  50. guard*: PackedItemId
  51. bitsize*: int
  52. alignment*: int # for alignment
  53. options*: TOptions
  54. position*: int
  55. offset*: int
  56. externalName*: LitId # instead of TLoc
  57. locFlags*: TLocFlags
  58. annex*: PackedLib
  59. when hasFFI:
  60. cname*: LitId
  61. constraint*: NodeId
  62. PackedType* = object
  63. kind*: TTypeKind
  64. callConv*: TCallingConvention
  65. #nodekind*: TNodeKind
  66. flags*: TTypeFlags
  67. types*: seq[PackedItemId]
  68. n*: NodeId
  69. #nodeflags*: TNodeFlags
  70. sym*: PackedItemId
  71. owner*: PackedItemId
  72. size*: BiggestInt
  73. align*: int16
  74. paddingAtEnd*: int16
  75. # not serialized: loc*: TLoc because it is backend-specific
  76. typeInst*: PackedItemId
  77. nonUniqueId*: int32
  78. PackedNode* = object # 28 bytes
  79. kind*: TNodeKind
  80. flags*: TNodeFlags
  81. operand*: int32 # for kind in {nkSym, nkSymDef}: SymId
  82. # for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
  83. # for kind in nkInt32Lit: direct value
  84. # for non-atom kinds: the number of nodes (for easy skipping)
  85. typeId*: PackedItemId
  86. info*: PackedLineInfo
  87. PackedTree* = object ## usually represents a full Nim module
  88. nodes*: seq[PackedNode]
  89. PackedInstantiation* = object
  90. key*, sym*: PackedItemId
  91. concreteTypes*: seq[PackedItemId]
  92. proc `==`*(a, b: SymId): bool {.borrow.}
  93. proc hash*(a: SymId): Hash {.borrow.}
  94. proc `==`*(a, b: NodePos): bool {.borrow.}
  95. #proc `==`*(a, b: PackedItemId): bool {.borrow.}
  96. proc `==`*(a, b: NodeId): bool {.borrow.}
  97. proc newTreeFrom*(old: PackedTree): PackedTree =
  98. result.nodes = @[]
  99. when false: result.sh = old.sh
  100. when false:
  101. proc declareSym*(tree: var PackedTree; kind: TSymKind;
  102. name: LitId; info: PackedLineInfo): SymId =
  103. result = SymId(tree.sh.syms.len)
  104. tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info)
  105. proc litIdFromName*(tree: PackedTree; name: string): LitId =
  106. result = tree.sh.strings.getOrIncl(name)
  107. proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) =
  108. tree.nodes.add PackedNode(kind: kind, info: info,
  109. operand: int32 getOrIncl(tree.sh.strings, token))
  110. proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) =
  111. tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
  112. proc throwAwayLastNode*(tree: var PackedTree) =
  113. tree.nodes.setLen(tree.nodes.len-1)
  114. proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
  115. tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info)
  116. proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
  117. tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info)
  118. proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) =
  119. tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info)
  120. proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
  121. tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info)
  122. proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
  123. proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) =
  124. # and this is why the IR is superior. We can copy subtrees
  125. # via a linear scan.
  126. let pos = n.int
  127. let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
  128. let d = dest.nodes.len
  129. dest.nodes.setLen(d + L)
  130. for i in 0..<L:
  131. dest.nodes[d+i] = tree.nodes[pos+i]
  132. when false:
  133. proc copySym*(dest: var PackedTree; tree: PackedTree; s: SymId): SymId =
  134. result = SymId(dest.sh.syms.len)
  135. assert int(s) < tree.sh.syms.len
  136. let oldSym = tree.sh.syms[s.int]
  137. dest.sh.syms.add oldSym
  138. type
  139. PatchPos = distinct int
  140. when false:
  141. proc prepare*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo): PatchPos =
  142. result = PatchPos tree.nodes.len
  143. tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
  144. proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
  145. result = PatchPos tree.nodes.len
  146. tree.nodes.add PackedNode(kind: kind, flags: flags, operand: 0, info: info,
  147. typeId: typeId)
  148. proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
  149. result = PatchPos dest.nodes.len
  150. dest.nodes.add source.nodes[sourcePos.int]
  151. proc patch*(tree: var PackedTree; pos: PatchPos) =
  152. let pos = pos.int
  153. assert tree.nodes[pos].kind > nkNilLit
  154. let distance = int32(tree.nodes.len - pos)
  155. tree.nodes[pos].operand = distance
  156. proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
  157. proc `[]`*(tree: PackedTree; i: int): lent PackedNode {.inline.} =
  158. tree.nodes[i]
  159. proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
  160. if tree.nodes[pos].kind > nkNilLit:
  161. assert tree.nodes[pos].operand > 0
  162. inc pos, tree.nodes[pos].operand
  163. else:
  164. inc pos
  165. iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
  166. var pos = n.int
  167. assert tree.nodes[pos].kind > nkNilLit
  168. let last = pos + tree.nodes[pos].operand
  169. inc pos
  170. while pos < last:
  171. yield NodePos pos
  172. nextChild tree, pos
  173. iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos =
  174. let patchPos = prepare(dest, tree, n)
  175. for x in sonsReadonly(tree, n): yield x
  176. patch dest, patchPos
  177. iterator isons*(dest: var PackedTree; tree: PackedTree;
  178. n: NodePos): (int, NodePos) =
  179. var i = 0
  180. for ch0 in sons(dest, tree, n):
  181. yield (i, ch0)
  182. inc i
  183. iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
  184. var pos = n.int
  185. assert tree.nodes[pos].kind > nkNilLit
  186. let last = pos + tree.nodes[pos].operand
  187. inc pos
  188. if pos < last:
  189. nextChild tree, pos
  190. while pos < last:
  191. yield NodePos pos
  192. nextChild tree, pos
  193. iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
  194. var count = 0
  195. for child in sonsReadonly(tree, n):
  196. inc count
  197. var pos = n.int
  198. assert tree.nodes[pos].kind > nkNilLit
  199. let last = pos + tree.nodes[pos].operand
  200. inc pos
  201. while pos < last and count > 2:
  202. yield NodePos pos
  203. dec count
  204. nextChild tree, pos
  205. proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
  206. # finding the parent of a node is rather easy:
  207. var pos = n.int - 1
  208. while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)):
  209. dec pos
  210. #assert pos >= 0, "node has no parent"
  211. result = NodePos(pos)
  212. template parent*(n: NodePos): NodePos = parentImpl(tree, n)
  213. proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool =
  214. var count = 0
  215. if tree.nodes[n.int].kind > nkNilLit:
  216. for child in sonsReadonly(tree, n): inc count
  217. result = count == x
  218. proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool =
  219. if tree.nodes[n.int].kind > nkNilLit:
  220. var count = 0
  221. for child in sonsReadonly(tree, n):
  222. inc count
  223. if count >= x: return true
  224. return false
  225. proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
  226. NodePos(n.int+1)
  227. proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
  228. tree.nodes[n.int].kind
  229. proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
  230. LitId tree.nodes[n.int].operand
  231. proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
  232. tree.nodes[n.int].info
  233. template typ*(n: NodePos): PackedItemId =
  234. tree.nodes[n.int].typeId
  235. template flags*(n: NodePos): TNodeFlags =
  236. tree.nodes[n.int].flags
  237. template operand*(n: NodePos): int32 =
  238. tree.nodes[n.int].operand
  239. proc span*(tree: PackedTree; pos: int): int {.inline.} =
  240. if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
  241. proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
  242. assert(not isAtom(tree, n.int))
  243. let a = n.int+1
  244. let b = a + span(tree, a)
  245. result = (NodePos a, NodePos b)
  246. proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
  247. assert(not isAtom(tree, n.int))
  248. let a = n.int+1
  249. let b = a + span(tree, a)
  250. let c = b + span(tree, b)
  251. result = (NodePos a, NodePos b, NodePos c)
  252. proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
  253. if tree.nodes[n.int].kind > nkNilLit:
  254. var count = 0
  255. for child in sonsReadonly(tree, n):
  256. if count == i: return child
  257. inc count
  258. assert false, "node has no i-th child"
  259. when false:
  260. proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} =
  261. tree.sh.strings[lit]
  262. template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
  263. template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
  264. template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand
  265. template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
  266. proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
  267. when false:
  268. # xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
  269. proc strLit*(tree: PackedTree; n: NodePos): lent string =
  270. assert n.kind == nkStrLit
  271. result = tree.sh.strings[LitId tree.nodes[n.int].operand]
  272. proc strVal*(tree: PackedTree; n: NodePos): string =
  273. assert n.kind == nkStrLit
  274. result = tree.sh.strings[LitId tree.nodes[n.int].operand]
  275. #result = cookedStrLit(raw)
  276. proc filenameVal*(tree: PackedTree; n: NodePos): string =
  277. case n.kind
  278. of nkStrLit:
  279. result = strVal(tree, n)
  280. of nkIdent:
  281. result = tree.sh.strings[n.litId]
  282. of nkSym:
  283. result = tree.sh.strings[tree.sh.syms[int n.symId].name]
  284. else:
  285. result = ""
  286. proc identAsStr*(tree: PackedTree; n: NodePos): lent string =
  287. assert n.kind == nkIdent
  288. result = tree.sh.strings[LitId tree.nodes[n.int].operand]
  289. const
  290. externIntLit* = {nkCharLit,
  291. nkIntLit,
  292. nkInt8Lit,
  293. nkInt16Lit,
  294. nkInt64Lit,
  295. nkUIntLit,
  296. nkUInt8Lit,
  297. nkUInt16Lit,
  298. nkUInt32Lit,
  299. nkUInt64Lit} # nkInt32Lit is missing by design!
  300. externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit}
  301. externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
  302. directIntLit* = nkInt32Lit
  303. when false:
  304. proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
  305. if n.kind == nkIdent:
  306. result = n.litId
  307. elif n.kind == nkSym:
  308. result = tree.sh.syms[int n.symId].name
  309. else:
  310. result = LitId(0)
  311. template identId*(n: NodePos): LitId = identIdImpl(tree, n)
  312. template copyInto*(dest, n, body) =
  313. let patchPos = prepare(dest, tree, n)
  314. body
  315. patch dest, patchPos
  316. template copyIntoKind*(dest, kind, info, body) =
  317. let patchPos = prepare(dest, kind, info)
  318. body
  319. patch dest, patchPos
  320. when false:
  321. proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool =
  322. let litId = tree.sh.strings.getKeyId(pragma)
  323. if litId == LitId(0):
  324. return false
  325. assert n.kind == nkPragma
  326. for ch0 in sonsReadonly(tree, n):
  327. if ch0.kind == nkExprColonExpr:
  328. if ch0.firstSon.identId == litId:
  329. return true
  330. elif ch0.identId == litId:
  331. return true
  332. proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
  333. when false:
  334. proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) =
  335. let patchPos = prepare(dest, nkError, n.info)
  336. dest.add nkStrLit, msg, n.info
  337. copyTree(dest, tree, n)
  338. patch dest, patchPos
  339. iterator allNodes*(tree: PackedTree): NodePos =
  340. var p = 0
  341. while p < tree.len:
  342. yield NodePos(p)
  343. let s = span(tree, p)
  344. inc p, s
  345. proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
  346. PackedItemId(module: LitId(0), item: item)