packed_ast.nim 12 KB

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