lowerings.nim 12 KB

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