lowerings.nim 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements common simple lowerings.
  10. const
  11. genPrefix* = ":tmp" # prefix for generated names
  12. import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs,
  13. lineinfos
  14. when defined(nimPreviewSlimSystem):
  15. import std/assertions
  16. proc newDeref*(n: PNode): PNode {.inline.} =
  17. result = newNodeIT(nkHiddenDeref, n.info, n.typ[0])
  18. result.add n
  19. proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
  20. if tup.kind == nkHiddenAddr:
  21. result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}))
  22. result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})[i])
  23. result[0].add tup[0]
  24. var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
  25. lit.intVal = i
  26. result[0].add lit
  27. else:
  28. result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
  29. abstractInst)[i])
  30. result.add copyTree(tup)
  31. var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
  32. lit.intVal = i
  33. result.add lit
  34. proc addVar*(father, v: PNode) =
  35. var vpart = newNodeI(nkIdentDefs, v.info, 3)
  36. vpart[0] = v
  37. vpart[1] = newNodeI(nkEmpty, v.info)
  38. vpart[2] = vpart[1]
  39. father.add vpart
  40. proc addVar*(father, v, value: PNode) =
  41. var vpart = newNodeI(nkIdentDefs, v.info, 3)
  42. vpart[0] = v
  43. vpart[1] = newNodeI(nkEmpty, v.info)
  44. vpart[2] = value
  45. father.add vpart
  46. proc newAsgnStmt*(le, ri: PNode): PNode =
  47. result = newNodeI(nkAsgn, le.info, 2)
  48. result[0] = le
  49. result[1] = ri
  50. proc newFastAsgnStmt*(le, ri: PNode): PNode =
  51. result = newNodeI(nkFastAsgn, le.info, 2)
  52. result[0] = le
  53. result[1] = ri
  54. proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode =
  55. result = newNodeI(nkFastAsgn, le.info, 2)
  56. result[0] = le
  57. result[1] = newNodeIT(nkCall, ri.info, ri.typ)
  58. result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove))
  59. result[1].add ri
  60. proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
  61. assert n.kind == nkVarTuple
  62. let value = n.lastSon
  63. result = newNodeI(nkStmtList, n.info)
  64. var tempAsNode: PNode
  65. let avoidTemp = value.kind == nkSym
  66. if avoidTemp:
  67. tempAsNode = value
  68. else:
  69. var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
  70. owner, value.info, g.config.options)
  71. temp.typ = skipTypes(value.typ, abstractInst)
  72. incl(temp.flags, sfFromGeneric)
  73. tempAsNode = newSymNode(temp)
  74. var v = newNodeI(nkVarSection, value.info)
  75. if not avoidTemp:
  76. v.addVar(tempAsNode, value)
  77. result.add(v)
  78. for i in 0..<n.len-2:
  79. let val = newTupleAccess(g, tempAsNode, i)
  80. if n[i].kind == nkSym: v.addVar(n[i], val)
  81. else: result.add newAsgnStmt(n[i], val)
  82. proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): PNode =
  83. ## Turns (value) into (let tmp = value; tmp) so that 'value' can be re-used
  84. ## freely, multiple times. This is frequently required and such a builtin would also be
  85. ## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
  86. result = newNodeIT(nkStmtListExpr, value.info, value.typ)
  87. var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
  88. owner, value.info, g.config.options)
  89. temp.typ = skipTypes(value.typ, abstractInst)
  90. incl(temp.flags, sfFromGeneric)
  91. var v = newNodeI(nkLetSection, value.info)
  92. let tempAsNode = newSymNode(temp)
  93. v.addVar(tempAsNode)
  94. result.add(v)
  95. result.add newAsgnStmt(tempAsNode, value)
  96. result.add tempAsNode
  97. proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
  98. result = newNodeI(nkBracketExpr, tup.info)
  99. result.add copyTree(tup)
  100. var lit = newNodeI(nkIntLit, tup.info)
  101. lit.intVal = i
  102. result.add lit
  103. proc newTryFinally*(body, final: PNode): PNode =
  104. result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
  105. proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
  106. let value = n.lastSon
  107. result = newNodeI(nkStmtList, n.info)
  108. var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options)
  109. var v = newNodeI(nkLetSection, value.info)
  110. let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
  111. var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
  112. vpart[0] = tempAsNode
  113. vpart[1] = newNodeI(nkEmpty, value.info)
  114. vpart[2] = value
  115. v.add vpart
  116. result.add(v)
  117. let lhs = n[0]
  118. for i in 0..<lhs.len:
  119. result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
  120. proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
  121. result = newNodeI(nkStmtList, n.info)
  122. # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
  123. var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options)
  124. temp.typ = n[1].typ
  125. incl(temp.flags, sfFromGeneric)
  126. incl(temp.flags, sfGenSym)
  127. var v = newNodeI(nkVarSection, n.info)
  128. let tempAsNode = newSymNode(temp)
  129. var vpart = newNodeI(nkIdentDefs, v.info, 3)
  130. vpart[0] = tempAsNode
  131. vpart[1] = newNodeI(nkEmpty, v.info)
  132. vpart[2] = n[1]
  133. v.add vpart
  134. result.add(v)
  135. result.add newFastAsgnStmt(n[1], n[2])
  136. result.add newFastAsgnStmt(n[2], tempAsNode)
  137. proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType =
  138. result = newType(tyObject, nextTypeId(idgen), owner)
  139. if final:
  140. rawAddSon(result, nil)
  141. incl result.flags, tfFinal
  142. else:
  143. rawAddSon(result, getCompilerProc(g, "RootObj").typ)
  144. result.n = newNodeI(nkRecList, info)
  145. let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
  146. nextSymId(idgen),
  147. owner, info, owner.options)
  148. incl s.flags, sfAnon
  149. s.typ = result
  150. result.sym = s
  151. template fieldCheck {.dirty.} =
  152. when false:
  153. if tfCheckedForDestructor in obj.flags:
  154. echo "missed field ", field.name.s
  155. writeStackTrace()
  156. proc rawAddField*(obj: PType; field: PSym) =
  157. assert field.kind == skField
  158. field.position = obj.n.len
  159. obj.n.add newSymNode(field)
  160. propagateToOwner(obj, field.typ)
  161. fieldCheck()
  162. proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
  163. # returns a[].field as a node
  164. assert field.kind == skField
  165. var deref = newNodeI(nkHiddenDeref, info)
  166. deref.typ = a.typ.skipTypes(abstractInst)[0]
  167. deref.add a
  168. result = newNodeI(nkDotExpr, info)
  169. result.add deref
  170. result.add newSymNode(field)
  171. result.typ = field.typ
  172. proc rawDirectAccess*(obj, field: PSym): PNode =
  173. # returns a.field as a node
  174. assert field.kind == skField
  175. result = newNodeI(nkDotExpr, field.info)
  176. result.add newSymNode(obj)
  177. result.add newSymNode(field)
  178. result.typ = field.typ
  179. proc lookupInRecord(n: PNode, id: ItemId): PSym =
  180. result = nil
  181. case n.kind
  182. of nkRecList:
  183. for i in 0..<n.len:
  184. result = lookupInRecord(n[i], id)
  185. if result != nil: return
  186. of nkRecCase:
  187. if n[0].kind != nkSym: return
  188. result = lookupInRecord(n[0], id)
  189. if result != nil: return
  190. for i in 1..<n.len:
  191. case n[i].kind
  192. of nkOfBranch, nkElse:
  193. result = lookupInRecord(lastSon(n[i]), id)
  194. if result != nil: return
  195. else: discard
  196. of nkSym:
  197. if n.sym.itemId.module == id.module and n.sym.itemId.item == -abs(id.item): result = n.sym
  198. else: discard
  199. proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym =
  200. # because of 'gensym' support, we have to mangle the name with its ID.
  201. # This is hacky but the clean solution is much more complex than it looks.
  202. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
  203. nextSymId(idgen), s.owner, s.info, s.options)
  204. field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
  205. let t = skipIntLit(s.typ, idgen)
  206. field.typ = t
  207. assert t.kind != tyTyped
  208. propagateToOwner(obj, t)
  209. field.position = obj.n.len
  210. # sfNoInit flag for skField is used in closureiterator codegen
  211. field.flags = s.flags * {sfCursor, sfNoInit}
  212. obj.n.add newSymNode(field)
  213. fieldCheck()
  214. result = field
  215. proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
  216. result = lookupInRecord(obj.n, s.itemId)
  217. if result == nil:
  218. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen),
  219. s.owner, s.info, s.options)
  220. field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
  221. let t = skipIntLit(s.typ, idgen)
  222. field.typ = t
  223. assert t.kind != tyTyped
  224. propagateToOwner(obj, t)
  225. field.position = obj.n.len
  226. obj.n.add newSymNode(field)
  227. result = field
  228. proc newDotExpr*(obj, b: PSym): PNode =
  229. result = newNodeI(nkDotExpr, obj.info)
  230. let field = lookupInRecord(obj.typ.n, b.itemId)
  231. assert field != nil, b.name.s
  232. result.add newSymNode(obj)
  233. result.add newSymNode(field)
  234. result.typ = field.typ
  235. proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
  236. # returns a[].b as a node
  237. var deref = newNodeI(nkHiddenDeref, info)
  238. deref.typ = a.typ.skipTypes(abstractInst)[0]
  239. var t = deref.typ.skipTypes(abstractInst)
  240. var field: PSym
  241. while true:
  242. assert t.kind == tyObject
  243. field = lookupInRecord(t.n, b)
  244. if field != nil: break
  245. t = t[0]
  246. if t == nil: break
  247. t = t.skipTypes(skipPtrs)
  248. #if field == nil:
  249. # echo "FIELD ", b
  250. # debug deref.typ
  251. assert field != nil
  252. deref.add a
  253. result = newNodeI(nkDotExpr, info)
  254. result.add deref
  255. result.add newSymNode(field)
  256. result.typ = field.typ
  257. proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
  258. # returns a[].b as a node
  259. var deref = newNodeI(nkHiddenDeref, info)
  260. deref.typ = a.typ.skipTypes(abstractInst)[0]
  261. var t = deref.typ.skipTypes(abstractInst)
  262. var field: PSym
  263. let bb = getIdent(cache, b)
  264. while true:
  265. assert t.kind == tyObject
  266. field = getSymFromList(t.n, bb)
  267. if field != nil: break
  268. t = t[0]
  269. if t == nil: break
  270. t = t.skipTypes(skipPtrs)
  271. #if field == nil:
  272. # echo "FIELD ", b
  273. # debug deref.typ
  274. assert field != nil
  275. deref.add a
  276. result = newNodeI(nkDotExpr, info)
  277. result.add deref
  278. result.add newSymNode(field)
  279. result.typ = field.typ
  280. proc getFieldFromObj*(t: PType; v: PSym): PSym =
  281. assert v.kind != skField
  282. var t = t
  283. while true:
  284. assert t.kind == tyObject
  285. result = lookupInRecord(t.n, v.itemId)
  286. if result != nil: break
  287. t = t[0]
  288. if t == nil: break
  289. t = t.skipTypes(skipPtrs)
  290. proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
  291. # returns a[].b as a node
  292. result = indirectAccess(a, b.itemId, info)
  293. proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
  294. result = indirectAccess(newSymNode(a), b, info)
  295. proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
  296. result = newNodeI(nkAddr, n.info, 1)
  297. result[0] = n
  298. result.typ = newType(typeKind, nextTypeId(idgen), n.typ.owner)
  299. result.typ.rawAddSon(n.typ)
  300. proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
  301. result = newNodeIT(k, n.info,
  302. n.typ.skipTypes(abstractInst)[0])
  303. result.add n
  304. proc callCodegenProc*(g: ModuleGraph; name: string;
  305. info: TLineInfo = unknownLineInfo;
  306. arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
  307. result = newNodeI(nkCall, info)
  308. let sym = magicsys.getCompilerProc(g, name)
  309. if sym == nil:
  310. localError(g.config, info, "system module needs: " & name)
  311. else:
  312. result.add newSymNode(sym)
  313. if arg1 != nil: result.add arg1
  314. if arg2 != nil: result.add arg2
  315. if arg3 != nil: result.add arg3
  316. if optionalArgs != nil:
  317. for i in 1..<optionalArgs.len-2:
  318. result.add optionalArgs[i]
  319. result.typ = sym.typ[0]
  320. proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
  321. result = nkIntLit.newIntNode(value)
  322. result.typ = getSysType(g, info, tyInt)
  323. proc genHigh*(g: ModuleGraph; n: PNode): PNode =
  324. if skipTypes(n.typ, abstractVar).kind == tyArray:
  325. result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
  326. else:
  327. result = newNodeI(nkCall, n.info, 2)
  328. result.typ = getSysType(g, n.info, tyInt)
  329. result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
  330. result[1] = n
  331. proc genLen*(g: ModuleGraph; n: PNode): PNode =
  332. if skipTypes(n.typ, abstractVar).kind == tyArray:
  333. result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
  334. else:
  335. result = newNodeI(nkCall, n.info, 2)
  336. result.typ = getSysType(g, n.info, tyInt)
  337. result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
  338. result[1] = n