packed_ast.nim 10 KB

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