lowerings.nim 12 KB

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