packed_ast.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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 std/[hashes, tables, strtabs]
  14. import bitabs, rodfiles
  15. import ".." / [ast, options]
  16. import ".." / nir / nirlineinfos
  17. when defined(nimPreviewSlimSystem):
  18. import std/assertions
  19. type
  20. SymId* = distinct int32
  21. ModuleId* = distinct int32
  22. NodePos* = distinct int
  23. NodeId* = distinct int32
  24. PackedItemId* = object
  25. module*: LitId # 0 if it's this module
  26. item*: int32 # same as the in-memory representation
  27. const
  28. nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
  29. const
  30. emptyNodeId* = NodeId(-1)
  31. type
  32. PackedLib* = object
  33. kind*: TLibKind
  34. generated*: bool
  35. isOverridden*: bool
  36. name*: LitId
  37. path*: NodeId
  38. PackedSym* = object
  39. kind*: TSymKind
  40. name*: LitId
  41. typ*: PackedItemId
  42. flags*: TSymFlags
  43. magic*: TMagic
  44. info*: PackedLineInfo
  45. ast*: NodeId
  46. owner*: PackedItemId
  47. guard*: PackedItemId
  48. bitsize*: int
  49. alignment*: int # for alignment
  50. options*: TOptions
  51. position*: int
  52. offset*: int32
  53. disamb*: int32
  54. externalName*: LitId # instead of TLoc
  55. locFlags*: TLocFlags
  56. annex*: PackedLib
  57. when hasFFI:
  58. cname*: LitId
  59. constraint*: NodeId
  60. instantiatedFrom*: PackedItemId
  61. PackedType* = object
  62. kind*: TTypeKind
  63. callConv*: TCallingConvention
  64. #nodekind*: TNodeKind
  65. flags*: TTypeFlags
  66. types*: seq[PackedItemId]
  67. n*: NodeId
  68. #nodeflags*: TNodeFlags
  69. sym*: PackedItemId
  70. owner*: PackedItemId
  71. size*: BiggestInt
  72. align*: int16
  73. paddingAtEnd*: int16
  74. # not serialized: loc*: TLoc because it is backend-specific
  75. typeInst*: PackedItemId
  76. nonUniqueId*: int32
  77. PackedNode* = object # 8 bytes
  78. x: uint32
  79. info*: PackedLineInfo
  80. PackedTree* = object ## usually represents a full Nim module
  81. nodes: seq[PackedNode]
  82. withFlags: seq[(int32, TNodeFlags)]
  83. withTypes: seq[(int32, PackedItemId)]
  84. PackedInstantiation* = object
  85. key*, sym*: PackedItemId
  86. concreteTypes*: seq[PackedItemId]
  87. const
  88. NodeKindBits = 8'u32
  89. NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
  90. template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
  91. template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
  92. template soperand*(n: PackedNode): int32 = int32(uoperand(n))
  93. template toX(k: TNodeKind; operand: uint32): uint32 =
  94. uint32(k) or (operand shl NodeKindBits)
  95. template toX(k: TNodeKind; operand: LitId): uint32 =
  96. uint32(k) or (operand.uint32 shl NodeKindBits)
  97. template typeId*(n: PackedNode): PackedItemId = n.typ
  98. proc `==`*(a, b: SymId): bool {.borrow.}
  99. proc hash*(a: SymId): Hash {.borrow.}
  100. proc `==`*(a, b: NodePos): bool {.borrow.}
  101. #proc `==`*(a, b: PackedItemId): bool {.borrow.}
  102. proc `==`*(a, b: NodeId): bool {.borrow.}
  103. proc newTreeFrom*(old: PackedTree): PackedTree =
  104. result = PackedTree(nodes: @[])
  105. when false: result.sh = old.sh
  106. proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
  107. tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
  108. proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
  109. tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
  110. proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
  111. tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
  112. proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
  113. type
  114. PatchPos = distinct int
  115. proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
  116. typeId: PackedItemId = nilItemId; info: PackedLineInfo;
  117. flags: TNodeFlags = {}) =
  118. t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
  119. if flags != {}:
  120. t.withFlags.add (t.nodes.len.int32 - 1, flags)
  121. if typeId != nilItemId:
  122. t.withTypes.add (t.nodes.len.int32 - 1, typeId)
  123. proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
  124. result = PatchPos tree.nodes.len
  125. tree.addNode(kind = kind, flags = flags, operand = 0, info = info, typeId = typeId)
  126. proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
  127. result = PatchPos dest.nodes.len
  128. dest.nodes.add source.nodes[sourcePos.int]
  129. proc patch*(tree: var PackedTree; pos: PatchPos) =
  130. let pos = pos.int
  131. let k = tree.nodes[pos].kind
  132. assert k > nkNilLit
  133. let distance = int32(tree.nodes.len - pos)
  134. assert distance > 0
  135. tree.nodes[pos].x = toX(k, cast[uint32](distance))
  136. proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
  137. proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
  138. tree.nodes[i.int]
  139. template rawSpan(n: PackedNode): int = int(uoperand(n))
  140. proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
  141. if tree.nodes[pos].kind > nkNilLit:
  142. assert tree.nodes[pos].uoperand > 0
  143. inc pos, tree.nodes[pos].rawSpan
  144. else:
  145. inc pos
  146. iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
  147. var pos = n.int
  148. assert tree.nodes[pos].kind > nkNilLit
  149. let last = pos + tree.nodes[pos].rawSpan
  150. inc pos
  151. while pos < last:
  152. yield NodePos pos
  153. nextChild tree, pos
  154. iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos =
  155. let patchPos = prepare(dest, tree, n)
  156. for x in sonsReadonly(tree, n): yield x
  157. patch dest, patchPos
  158. iterator isons*(dest: var PackedTree; tree: PackedTree;
  159. n: NodePos): (int, NodePos) =
  160. var i = 0
  161. for ch0 in sons(dest, tree, n):
  162. yield (i, ch0)
  163. inc i
  164. iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
  165. var pos = n.int
  166. assert tree.nodes[pos].kind > nkNilLit
  167. let last = pos + tree.nodes[pos].rawSpan
  168. inc pos
  169. if pos < last:
  170. nextChild tree, pos
  171. while pos < last:
  172. yield NodePos pos
  173. nextChild tree, pos
  174. iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
  175. var count = 0
  176. for child in sonsReadonly(tree, n):
  177. inc count
  178. var pos = n.int
  179. assert tree.nodes[pos].kind > nkNilLit
  180. let last = pos + tree.nodes[pos].rawSpan
  181. inc pos
  182. while pos < last and count > 2:
  183. yield NodePos pos
  184. dec count
  185. nextChild tree, pos
  186. proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
  187. # finding the parent of a node is rather easy:
  188. var pos = n.int - 1
  189. while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
  190. dec pos
  191. #assert pos >= 0, "node has no parent"
  192. result = NodePos(pos)
  193. template parent*(n: NodePos): NodePos = parentImpl(tree, n)
  194. proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool =
  195. var count = 0
  196. if tree.nodes[n.int].kind > nkNilLit:
  197. for child in sonsReadonly(tree, n): inc count
  198. result = count == x
  199. proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool =
  200. if tree.nodes[n.int].kind > nkNilLit:
  201. var count = 0
  202. for child in sonsReadonly(tree, n):
  203. inc count
  204. if count >= x: return true
  205. return false
  206. proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
  207. NodePos(n.int+1)
  208. proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
  209. tree.nodes[n.int].kind
  210. proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
  211. LitId tree.nodes[n.int].uoperand
  212. proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
  213. tree.nodes[n.int].info
  214. proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
  215. for x in tree.withTypes:
  216. if x[0] == int32(n): return x[1]
  217. if x[0] > int32(n): return nilItemId
  218. return nilItemId
  219. proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
  220. for x in tree.withFlags:
  221. if x[0] == int32(n): return x[1]
  222. if x[0] > int32(n): return {}
  223. return {}
  224. template typ*(n: NodePos): PackedItemId =
  225. tree.findType(n)
  226. template flags*(n: NodePos): TNodeFlags =
  227. tree.findFlags(n)
  228. template uoperand*(n: NodePos): uint32 =
  229. tree.nodes[n.int].uoperand
  230. proc span*(tree: PackedTree; pos: int): int {.inline.} =
  231. if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
  232. proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
  233. assert(not isAtom(tree, n.int))
  234. let a = n.int+1
  235. let b = a + span(tree, a)
  236. result = (NodePos a, NodePos b)
  237. proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
  238. assert(not isAtom(tree, n.int))
  239. let a = n.int+1
  240. let b = a + span(tree, a)
  241. let c = b + span(tree, b)
  242. result = (NodePos a, NodePos b, NodePos c)
  243. proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
  244. result = default(NodePos)
  245. if tree.nodes[n.int].kind > nkNilLit:
  246. var count = 0
  247. for child in sonsReadonly(tree, n):
  248. if count == i: return child
  249. inc count
  250. assert false, "node has no i-th child"
  251. when false:
  252. proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} =
  253. tree.sh.strings[lit]
  254. template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
  255. template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
  256. template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
  257. template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
  258. proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
  259. const
  260. externIntLit* = {nkCharLit,
  261. nkIntLit,
  262. nkInt8Lit,
  263. nkInt16Lit,
  264. nkInt32Lit,
  265. nkInt64Lit,
  266. nkUIntLit,
  267. nkUInt8Lit,
  268. nkUInt16Lit,
  269. nkUInt32Lit,
  270. nkUInt64Lit}
  271. externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
  272. externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
  273. directIntLit* = nkNone
  274. template copyInto*(dest, n, body) =
  275. let patchPos = prepare(dest, tree, n)
  276. body
  277. patch dest, patchPos
  278. template copyIntoKind*(dest, kind, info, body) =
  279. let patchPos = prepare(dest, kind, info)
  280. body
  281. patch dest, patchPos
  282. proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
  283. iterator allNodes*(tree: PackedTree): NodePos =
  284. var p = 0
  285. while p < tree.len:
  286. yield NodePos(p)
  287. let s = span(tree, p)
  288. inc p, s
  289. proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
  290. PackedItemId(module: LitId(0), item: item)
  291. proc load*(f: var RodFile; t: var PackedTree) =
  292. loadSeq f, t.nodes
  293. loadSeq f, t.withFlags
  294. loadSeq f, t.withTypes
  295. proc store*(f: var RodFile; t: PackedTree) =
  296. storeSeq f, t.nodes
  297. storeSeq f, t.withFlags
  298. storeSeq f, t.withTypes