transf.nim 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  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 the transformator. It transforms the syntax tree
  10. # to ease the work of the code generators. Does some transformations:
  11. #
  12. # * inlines iterators
  13. # * inlines constants
  14. # * performs constant folding
  15. # * converts "continue" to "break"; disambiguates "break"
  16. # * introduces method dispatchers
  17. # * performs lambda lifting for closure support
  18. # * transforms 'defer' into a 'try finally' statement
  19. import
  20. intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups,
  21. idents, renderer, types, passes, semfold, magicsys, cgmeth,
  22. lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters,
  23. modulegraphs, lineinfos
  24. type
  25. PTransNode* = distinct PNode
  26. PTransCon = ref TTransCon
  27. TTransCon{.final.} = object # part of TContext; stackable
  28. mapping: TIdNodeTable # mapping from symbols to nodes
  29. owner: PSym # current owner
  30. forStmt: PNode # current for stmt
  31. forLoopBody: PTransNode # transformed for loop body
  32. yieldStmts: int # we count the number of yield statements,
  33. # because we need to introduce new variables
  34. # if we encounter the 2nd yield statement
  35. next: PTransCon # for stacking
  36. TTransfContext = object of passes.TPassContext
  37. module: PSym
  38. transCon: PTransCon # top of a TransCon stack
  39. inlining: int # > 0 if we are in inlining context (copy vars)
  40. nestedProcs: int # > 0 if we are in a nested proc
  41. contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
  42. deferDetected, tooEarly, needsDestroyPass: bool
  43. graph: ModuleGraph
  44. PTransf = ref TTransfContext
  45. proc newTransNode(a: PNode): PTransNode {.inline.} =
  46. result = PTransNode(shallowCopy(a))
  47. proc newTransNode(kind: TNodeKind, info: TLineInfo,
  48. sons: int): PTransNode {.inline.} =
  49. var x = newNodeI(kind, info)
  50. newSeq(x.sons, sons)
  51. result = x.PTransNode
  52. proc newTransNode(kind: TNodeKind, n: PNode,
  53. sons: int): PTransNode {.inline.} =
  54. var x = newNodeIT(kind, n.info, n.typ)
  55. newSeq(x.sons, sons)
  56. x.typ = n.typ
  57. result = x.PTransNode
  58. proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
  59. var n = PNode(a)
  60. n.sons[i] = PNode(x)
  61. proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
  62. var n = PNode(a)
  63. result = n.sons[i].PTransNode
  64. proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
  65. proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
  66. proc newTransCon(owner: PSym): PTransCon =
  67. assert owner != nil
  68. new(result)
  69. initIdNodeTable(result.mapping)
  70. result.owner = owner
  71. proc pushTransCon(c: PTransf, t: PTransCon) =
  72. t.next = c.transCon
  73. c.transCon = t
  74. proc popTransCon(c: PTransf) =
  75. if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
  76. c.transCon = c.transCon.next
  77. proc getCurrOwner(c: PTransf): PSym =
  78. if c.transCon != nil: result = c.transCon.owner
  79. else: result = c.module
  80. proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
  81. let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), getCurrOwner(c), info)
  82. r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
  83. incl(r.flags, sfFromGeneric)
  84. let owner = getCurrOwner(c)
  85. if owner.isIterator and not c.tooEarly:
  86. result = freshVarForClosureIter(c.graph, r, owner)
  87. else:
  88. result = newSymNode(r)
  89. proc transform(c: PTransf, n: PNode): PTransNode
  90. proc transformSons(c: PTransf, n: PNode): PTransNode =
  91. result = newTransNode(n)
  92. for i in countup(0, sonsLen(n)-1):
  93. result[i] = transform(c, n.sons[i])
  94. proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
  95. result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
  96. result[0] = PTransNode(le)
  97. result[1] = ri
  98. proc transformSymAux(c: PTransf, n: PNode): PNode =
  99. let s = n.sym
  100. if s.typ != nil and s.typ.callConv == ccClosure:
  101. if s.kind == skIterator:
  102. if c.tooEarly: return n
  103. else: return liftIterSym(c.graph, n, getCurrOwner(c))
  104. elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
  105. # top level .closure procs are still somewhat supported for 'Nake':
  106. return makeClosure(c.graph, s, nil, n.info)
  107. #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
  108. # echo n.info, " come heer for ", c.tooEarly
  109. # if not c.tooEarly:
  110. var b: PNode
  111. var tc = c.transCon
  112. if sfBorrow in s.flags and s.kind in routineKinds:
  113. # simply exchange the symbol:
  114. b = s.getBody
  115. if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
  116. b = newSymNode(b.sym, n.info)
  117. else:
  118. b = n
  119. while tc != nil:
  120. result = idNodeTableGet(tc.mapping, b.sym)
  121. if result != nil:
  122. # this slightly convoluted way ensures the line info stays correct:
  123. if result.kind == nkSym:
  124. result = copyNode(result)
  125. result.info = n.info
  126. return
  127. tc = tc.next
  128. result = b
  129. proc transformSym(c: PTransf, n: PNode): PTransNode =
  130. result = PTransNode(transformSymAux(c, n))
  131. proc freshVar(c: PTransf; v: PSym): PNode =
  132. let owner = getCurrOwner(c)
  133. if owner.isIterator and not c.tooEarly:
  134. result = freshVarForClosureIter(c.graph, v, owner)
  135. else:
  136. var newVar = copySym(v)
  137. incl(newVar.flags, sfFromGeneric)
  138. newVar.owner = owner
  139. result = newSymNode(newVar)
  140. proc transformVarSection(c: PTransf, v: PNode): PTransNode =
  141. result = newTransNode(v)
  142. for i in countup(0, sonsLen(v)-1):
  143. var it = v.sons[i]
  144. if it.kind == nkCommentStmt:
  145. result[i] = PTransNode(it)
  146. elif it.kind == nkIdentDefs:
  147. if it.sons[0].kind == nkSym:
  148. internalAssert(c.graph.config, it.len == 3)
  149. let x = freshVar(c, it.sons[0].sym)
  150. idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
  151. var defs = newTransNode(nkIdentDefs, it.info, 3)
  152. if importantComments(c.graph.config):
  153. # keep documentation information:
  154. PNode(defs).comment = it.comment
  155. defs[0] = x.PTransNode
  156. defs[1] = it.sons[1].PTransNode
  157. defs[2] = transform(c, it.sons[2])
  158. if x.kind == nkSym: x.sym.ast = defs[2].PNode
  159. result[i] = defs
  160. else:
  161. # has been transformed into 'param.x' for closure iterators, so just
  162. # transform it:
  163. result[i] = transform(c, it)
  164. else:
  165. if it.kind != nkVarTuple:
  166. internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
  167. var L = sonsLen(it)
  168. var defs = newTransNode(it.kind, it.info, L)
  169. for j in countup(0, L-3):
  170. let x = freshVar(c, it.sons[j].sym)
  171. idNodeTablePut(c.transCon.mapping, it.sons[j].sym, x)
  172. defs[j] = x.PTransNode
  173. assert(it.sons[L-2].kind == nkEmpty)
  174. defs[L-2] = newNodeI(nkEmpty, it.info).PTransNode
  175. defs[L-1] = transform(c, it.sons[L-1])
  176. result[i] = defs
  177. proc transformConstSection(c: PTransf, v: PNode): PTransNode =
  178. result = newTransNode(v)
  179. for i in countup(0, sonsLen(v)-1):
  180. var it = v.sons[i]
  181. if it.kind == nkCommentStmt:
  182. result[i] = PTransNode(it)
  183. else:
  184. if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
  185. if it.sons[0].kind != nkSym:
  186. internalError(c.graph.config, it.info, "transformConstSection")
  187. result[i] = PTransNode(it)
  188. proc hasContinue(n: PNode): bool =
  189. case n.kind
  190. of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
  191. of nkContinueStmt: result = true
  192. else:
  193. for i in countup(0, sonsLen(n) - 1):
  194. if hasContinue(n.sons[i]): return true
  195. proc newLabel(c: PTransf, n: PNode): PSym =
  196. result = newSym(skLabel, nil, getCurrOwner(c), n.info)
  197. result.name = getIdent(c.graph.cache, genPrefix & $result.id)
  198. proc freshLabels(c: PTransf, n: PNode; symMap: var TIdTable) =
  199. if n.kind in {nkBlockStmt, nkBlockExpr}:
  200. if n.sons[0].kind == nkSym:
  201. let x = newLabel(c, n[0])
  202. idTablePut(symMap, n[0].sym, x)
  203. n.sons[0].sym = x
  204. if n.kind == nkSym and n.sym.kind == skLabel:
  205. let x = PSym(idTableGet(symMap, n.sym))
  206. if x != nil: n.sym = x
  207. else:
  208. for i in 0 ..< safeLen(n): freshLabels(c, n.sons[i], symMap)
  209. proc transformBlock(c: PTransf, n: PNode): PTransNode =
  210. var labl: PSym
  211. if n.sons[0].kind != nkEmpty:
  212. # already named block? -> Push symbol on the stack:
  213. labl = n.sons[0].sym
  214. else:
  215. labl = newLabel(c, n)
  216. c.breakSyms.add(labl)
  217. result = transformSons(c, n)
  218. discard c.breakSyms.pop
  219. result[0] = newSymNode(labl).PTransNode
  220. proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
  221. # What if it contains "continue" and "break"? "break" needs
  222. # an explicit label too, but not the same!
  223. # We fix this here by making every 'break' belong to its enclosing loop
  224. # and changing all breaks that belong to a 'block' by annotating it with
  225. # a label (if it hasn't one already).
  226. if hasContinue(n):
  227. let labl = newLabel(c, n)
  228. c.contSyms.add(labl)
  229. result = newTransNode(nkBlockStmt, n.info, 2)
  230. result[0] = newSymNode(labl).PTransNode
  231. result[1] = transform(c, n)
  232. discard c.contSyms.pop()
  233. else:
  234. result = transform(c, n)
  235. proc transformWhile(c: PTransf; n: PNode): PTransNode =
  236. if c.inlining > 0:
  237. result = transformSons(c, n)
  238. else:
  239. let labl = newLabel(c, n)
  240. c.breakSyms.add(labl)
  241. result = newTransNode(nkBlockStmt, n.info, 2)
  242. result[0] = newSymNode(labl).PTransNode
  243. var body = newTransNode(n)
  244. for i in 0..n.len-2:
  245. body[i] = transform(c, n.sons[i])
  246. body[n.len-1] = transformLoopBody(c, n.sons[n.len-1])
  247. result[1] = body
  248. discard c.breakSyms.pop
  249. proc transformBreak(c: PTransf, n: PNode): PTransNode =
  250. if n.sons[0].kind != nkEmpty or c.inlining > 0:
  251. result = n.PTransNode
  252. when false:
  253. let lablCopy = idNodeTableGet(c.transCon.mapping, n.sons[0].sym)
  254. if lablCopy.isNil:
  255. result = n.PTransNode
  256. else:
  257. result = newTransNode(n.kind, n.info, 1)
  258. result[0] = lablCopy.PTransNode
  259. elif c.breakSyms.len > 0:
  260. # this check can fail for 'nim check'
  261. let labl = c.breakSyms[c.breakSyms.high]
  262. result = transformSons(c, n)
  263. result[0] = newSymNode(labl).PTransNode
  264. else:
  265. result = n.PTransNode
  266. proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
  267. # XXX: BUG: what if `n` is an expression with side-effects?
  268. for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
  269. add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
  270. transform(c, newTupleAccess(c.graph, n, i))))
  271. proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
  272. case n.kind
  273. of nkSym:
  274. result = transformSym(c, n)
  275. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
  276. # nothing to be done for leaves:
  277. result = PTransNode(n)
  278. of nkVarSection, nkLetSection:
  279. result = transformVarSection(c, n)
  280. of nkClosure:
  281. # it can happen that for-loop-inlining produced a fresh
  282. # set of variables, including some computed environment
  283. # (bug #2604). We need to patch this environment here too:
  284. let a = n[1]
  285. if a.kind == nkSym:
  286. n.sons[1] = transformSymAux(c, a)
  287. return PTransNode(n)
  288. else:
  289. result = newTransNode(n)
  290. for i in countup(0, sonsLen(n)-1):
  291. result[i] = introduceNewLocalVars(c, n.sons[i])
  292. proc transformYield(c: PTransf, n: PNode): PTransNode =
  293. result = newTransNode(nkStmtList, n.info, 0)
  294. var e = n.sons[0]
  295. # c.transCon.forStmt.len == 3 means that there is one for loop variable
  296. # and thus no tuple unpacking:
  297. if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
  298. if skipTypes(e.typ, {tyGenericInst, tyAlias, tySink}).kind == tyTuple and
  299. c.transCon.forStmt.len != 3:
  300. e = skipConv(e)
  301. if e.kind in {nkPar, nkTupleConstr}:
  302. for i in countup(0, sonsLen(e) - 1):
  303. var v = e.sons[i]
  304. if v.kind == nkExprColonExpr: v = v.sons[1]
  305. add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
  306. transform(c, v)))
  307. else:
  308. unpackTuple(c, e, result)
  309. else:
  310. var x = transform(c, e)
  311. add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
  312. inc(c.transCon.yieldStmts)
  313. if c.transCon.yieldStmts <= 1:
  314. # common case
  315. add(result, c.transCon.forLoopBody)
  316. else:
  317. # we need to introduce new local variables:
  318. add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
  319. proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
  320. result = transformSons(c, n)
  321. if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
  322. var n = result.PNode
  323. case n.sons[0].kind
  324. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  325. var m = n.sons[0].sons[0]
  326. if m.kind == a or m.kind == b:
  327. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  328. n.sons[0].sons[0] = m.sons[0]
  329. result = PTransNode(n.sons[0])
  330. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  331. PNode(result).typ = n.typ
  332. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  333. PNode(result).typ = toVar(PNode(result).typ)
  334. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  335. var m = n.sons[0].sons[1]
  336. if m.kind == a or m.kind == b:
  337. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  338. n.sons[0].sons[1] = m.sons[0]
  339. result = PTransNode(n.sons[0])
  340. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  341. PNode(result).typ = n.typ
  342. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  343. PNode(result).typ = toVar(PNode(result).typ)
  344. else:
  345. if n.sons[0].kind == a or n.sons[0].kind == b:
  346. # addr ( deref ( x )) --> x
  347. result = PTransNode(n.sons[0].sons[0])
  348. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  349. PNode(result).typ = n.typ
  350. proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
  351. ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  352. ## a closure.
  353. # we cannot generate a proper thunk here for GC-safety reasons
  354. # (see internal documentation):
  355. if c.graph.config.cmd == cmdCompileToJS: return prc
  356. result = newNodeIT(nkClosure, prc.info, dest)
  357. var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  358. conv.add(newNodeI(nkEmpty, prc.info))
  359. conv.add(prc)
  360. if prc.kind == nkClosure:
  361. internalError(c.graph.config, prc.info, "closure to closure created")
  362. result.add(conv)
  363. result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
  364. proc transformConv(c: PTransf, n: PNode): PTransNode =
  365. # numeric types need range checks:
  366. var dest = skipTypes(n.typ, abstractVarRange)
  367. var source = skipTypes(n.sons[1].typ, abstractVarRange)
  368. case dest.kind
  369. of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
  370. # we don't include uint and uint64 here as these are no ordinal types ;-)
  371. if not isOrdinalType(source):
  372. # float -> int conversions. ugh.
  373. result = transformSons(c, n)
  374. elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n.sons[1].typ) and
  375. lastOrd(c.graph.config, n.sons[1].typ) <= lastOrd(c.graph.config, n.typ):
  376. # BUGFIX: simply leave n as it is; we need a nkConv node,
  377. # but no range check:
  378. result = transformSons(c, n)
  379. else:
  380. # generate a range check:
  381. if dest.kind == tyInt64 or source.kind == tyInt64:
  382. result = newTransNode(nkChckRange64, n, 3)
  383. else:
  384. result = newTransNode(nkChckRange, n, 3)
  385. dest = skipTypes(n.typ, abstractVar)
  386. result[0] = transform(c, n.sons[1])
  387. result[1] = newIntTypeNode(nkIntLit, firstOrd(c.graph.config, dest), dest).PTransNode
  388. result[2] = newIntTypeNode(nkIntLit, lastOrd(c.graph.config, dest), dest).PTransNode
  389. of tyFloat..tyFloat128:
  390. # XXX int64 -> float conversion?
  391. if skipTypes(n.typ, abstractVar).kind == tyRange:
  392. result = newTransNode(nkChckRangeF, n, 3)
  393. dest = skipTypes(n.typ, abstractVar)
  394. result[0] = transform(c, n.sons[1])
  395. result[1] = copyTree(dest.n.sons[0]).PTransNode
  396. result[2] = copyTree(dest.n.sons[1]).PTransNode
  397. else:
  398. result = transformSons(c, n)
  399. of tyOpenArray, tyVarargs:
  400. result = transform(c, n.sons[1])
  401. PNode(result).typ = takeType(n.typ, n.sons[1].typ)
  402. #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
  403. # " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
  404. of tyCString:
  405. if source.kind == tyString:
  406. result = newTransNode(nkStringToCString, n, 1)
  407. result[0] = transform(c, n.sons[1])
  408. else:
  409. result = transformSons(c, n)
  410. of tyString:
  411. if source.kind == tyCString:
  412. result = newTransNode(nkCStringToString, n, 1)
  413. result[0] = transform(c, n.sons[1])
  414. else:
  415. result = transformSons(c, n)
  416. of tyRef, tyPtr:
  417. dest = skipTypes(dest, abstractPtrs)
  418. source = skipTypes(source, abstractPtrs)
  419. if source.kind == tyObject:
  420. var diff = inheritanceDiff(dest, source)
  421. if diff < 0:
  422. result = newTransNode(nkObjUpConv, n, 1)
  423. result[0] = transform(c, n.sons[1])
  424. elif diff > 0 and diff != high(int):
  425. result = newTransNode(nkObjDownConv, n, 1)
  426. result[0] = transform(c, n.sons[1])
  427. else:
  428. result = transform(c, n.sons[1])
  429. else:
  430. result = transformSons(c, n)
  431. of tyObject:
  432. var diff = inheritanceDiff(dest, source)
  433. if diff < 0:
  434. result = newTransNode(nkObjUpConv, n, 1)
  435. result[0] = transform(c, n.sons[1])
  436. elif diff > 0 and diff != high(int):
  437. result = newTransNode(nkObjDownConv, n, 1)
  438. result[0] = transform(c, n.sons[1])
  439. else:
  440. result = transform(c, n.sons[1])
  441. of tyGenericParam, tyOrdinal:
  442. result = transform(c, n.sons[1])
  443. # happens sometimes for generated assignments, etc.
  444. of tyProc:
  445. result = transformSons(c, n)
  446. if dest.callConv == ccClosure and source.callConv == ccDefault:
  447. result = generateThunk(c, result[1].PNode, dest).PTransNode
  448. else:
  449. result = transformSons(c, n)
  450. type
  451. TPutArgInto = enum
  452. paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
  453. proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  454. # This analyses how to treat the mapping "formal <-> arg" in an
  455. # inline context.
  456. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
  457. if arg.kind == nkStmtListExpr:
  458. return paComplexOpenarray
  459. return paDirectMapping # XXX really correct?
  460. # what if ``arg`` has side-effects?
  461. case arg.kind
  462. of nkEmpty..nkNilLit:
  463. result = paDirectMapping
  464. of nkPar, nkTupleConstr, nkCurly, nkBracket:
  465. result = paFastAsgn
  466. for i in countup(0, sonsLen(arg) - 1):
  467. if putArgInto(arg.sons[i], formal) != paDirectMapping: return
  468. result = paDirectMapping
  469. else:
  470. if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
  471. else: result = paFastAsgn
  472. proc findWrongOwners(c: PTransf, n: PNode) =
  473. if n.kind == nkVarSection:
  474. let x = n.sons[0].sons[0]
  475. if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
  476. internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
  477. x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  478. else:
  479. for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
  480. proc transformFor(c: PTransf, n: PNode): PTransNode =
  481. # generate access statements for the parameters (unless they are constant)
  482. # put mapping from formal parameters to actual parameters
  483. if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
  484. var length = sonsLen(n)
  485. var call = n.sons[length - 2]
  486. let labl = newLabel(c, n)
  487. result = newTransNode(nkBlockStmt, n.info, 2)
  488. result[0] = newSymNode(labl).PTransNode
  489. if call.typ.isNil:
  490. # see bug #3051
  491. result[1] = newNode(nkEmpty).PTransNode
  492. return result
  493. c.breakSyms.add(labl)
  494. if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
  495. call.sons[0].typ.callConv == ccClosure:
  496. n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
  497. n.sons[length-2] = transform(c, n.sons[length-2]).PNode
  498. result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
  499. discard c.breakSyms.pop
  500. return result
  501. #echo "transforming: ", renderTree(n)
  502. var stmtList = newTransNode(nkStmtList, n.info, 0)
  503. result[1] = stmtList
  504. var loopBody = transformLoopBody(c, n.sons[length-1])
  505. discard c.breakSyms.pop
  506. var v = newNodeI(nkVarSection, n.info)
  507. for i in countup(0, length - 3):
  508. addVar(v, copyTree(n.sons[i])) # declare new vars
  509. add(stmtList, v.PTransNode)
  510. # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  511. # iterator!
  512. let iter = call.sons[0].sym
  513. var newC = newTransCon(getCurrOwner(c))
  514. newC.forStmt = n
  515. newC.forLoopBody = loopBody
  516. # this can fail for 'nimsuggest' and 'check':
  517. if iter.kind != skIterator: return result
  518. # generate access statements for the parameters (unless they are constant)
  519. pushTransCon(c, newC)
  520. for i in countup(1, sonsLen(call) - 1):
  521. var arg = transform(c, call.sons[i]).PNode
  522. let ff = skipTypes(iter.typ, abstractInst)
  523. # can happen for 'nim check':
  524. if i >= ff.n.len: return result
  525. var formal = ff.n.sons[i].sym
  526. case putArgInto(arg, formal.typ)
  527. of paDirectMapping:
  528. idNodeTablePut(newC.mapping, formal, arg)
  529. of paFastAsgn:
  530. # generate a temporary and produce an assignment statement:
  531. var temp = newTemp(c, formal.typ, formal.info)
  532. addVar(v, temp)
  533. add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
  534. idNodeTablePut(newC.mapping, formal, temp)
  535. of paVarAsgn:
  536. assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
  537. idNodeTablePut(newC.mapping, formal, arg)
  538. # XXX BUG still not correct if the arg has a side effect!
  539. of paComplexOpenarray:
  540. let typ = newType(tySequence, formal.owner)
  541. addSonSkipIntLit(typ, formal.typ.sons[0])
  542. var temp = newTemp(c, typ, formal.info)
  543. addVar(v, temp)
  544. add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
  545. idNodeTablePut(newC.mapping, formal, temp)
  546. var body = iter.getBody.copyTree
  547. pushInfoContext(c.graph.config, n.info)
  548. # XXX optimize this somehow. But the check "c.inlining" is not correct:
  549. var symMap: TIdTable
  550. initIdTable symMap
  551. freshLabels(c, body, symMap)
  552. inc(c.inlining)
  553. add(stmtList, transform(c, body))
  554. #findWrongOwners(c, stmtList.pnode)
  555. dec(c.inlining)
  556. popInfoContext(c.graph.config)
  557. popTransCon(c)
  558. # echo "transformed: ", stmtList.PNode.renderTree
  559. proc transformCase(c: PTransf, n: PNode): PTransNode =
  560. # removes `elif` branches of a case stmt
  561. # adds ``else: nil`` if needed for the code generator
  562. result = newTransNode(nkCaseStmt, n, 0)
  563. var ifs = PTransNode(nil)
  564. for i in 0 .. sonsLen(n)-1:
  565. var it = n.sons[i]
  566. var e = transform(c, it)
  567. case it.kind
  568. of nkElifBranch:
  569. if ifs.PNode == nil:
  570. # Generate the right node depending on whether `n` is used as a stmt or
  571. # as an expr
  572. let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
  573. ifs = newTransNode(kind, it.info, 0)
  574. ifs.PNode.typ = n.typ
  575. ifs.add(e)
  576. of nkElse:
  577. if ifs.PNode == nil: result.add(e)
  578. else: ifs.add(e)
  579. else:
  580. result.add(e)
  581. if ifs.PNode != nil:
  582. var elseBranch = newTransNode(nkElse, n.info, 1)
  583. elseBranch[0] = ifs
  584. result.add(elseBranch)
  585. elif result.PNode.lastSon.kind != nkElse and not (
  586. skipTypes(n.sons[0].typ, abstractVarRange).kind in
  587. {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
  588. # fix a stupid code gen bug by normalizing:
  589. var elseBranch = newTransNode(nkElse, n.info, 1)
  590. elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
  591. add(result, elseBranch)
  592. proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
  593. # XXX this is really bad; transf should use a proper AST visitor
  594. if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
  595. result = n.PTransNode
  596. else:
  597. result = newTransNode(n)
  598. for i in 0 ..< n.len:
  599. result[i] = transform(c, skipConv(n.sons[i]))
  600. proc getMergeOp(n: PNode): PSym =
  601. case n.kind
  602. of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
  603. nkCallStrLit:
  604. if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
  605. result = n.sons[0].sym
  606. else: discard
  607. proc flattenTreeAux(d, a: PNode, op: PSym) =
  608. let op2 = getMergeOp(a)
  609. if op2 != nil and
  610. (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
  611. for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
  612. else:
  613. addSon(d, copyTree(a))
  614. proc flattenTree(root: PNode): PNode =
  615. let op = getMergeOp(root)
  616. if op != nil:
  617. result = copyNode(root)
  618. addSon(result, copyTree(root.sons[0]))
  619. flattenTreeAux(result, root, op)
  620. else:
  621. result = root
  622. proc transformCall(c: PTransf, n: PNode): PTransNode =
  623. var n = flattenTree(n)
  624. let op = getMergeOp(n)
  625. let magic = getMagic(n)
  626. if op != nil and op.magic != mNone and n.len >= 3:
  627. result = newTransNode(nkCall, n, 0)
  628. add(result, transform(c, n.sons[0]))
  629. var j = 1
  630. while j < sonsLen(n):
  631. var a = transform(c, n.sons[j]).PNode
  632. inc(j)
  633. if isConstExpr(a):
  634. while (j < sonsLen(n)):
  635. let b = transform(c, n.sons[j]).PNode
  636. if not isConstExpr(b): break
  637. a = evalOp(op.magic, n, a, b, nil, c.graph)
  638. inc(j)
  639. add(result, a.PTransNode)
  640. if len(result) == 2: result = result[1]
  641. elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
  642. # for bindSym(myconst) we MUST NOT perform constant folding:
  643. result = n.PTransNode
  644. elif magic == mProcCall:
  645. # but do not change to its dispatcher:
  646. result = transformSons(c, n[1])
  647. else:
  648. let s = transformSons(c, n).PNode
  649. # bugfix: check after 'transformSons' if it's still a method call:
  650. # use the dispatcher for the call:
  651. if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
  652. when false:
  653. let t = lastSon(s.sons[0].sym.ast)
  654. if t.kind != nkSym or sfDispatcher notin t.sym.flags:
  655. methodDef(s.sons[0].sym, false)
  656. result = methodCall(s, c.graph.config).PTransNode
  657. else:
  658. result = s.PTransNode
  659. proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
  660. result = transformSons(c, n)
  661. if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
  662. let excTypeNode = n[0][1]
  663. let actions = newTransNode(nkStmtListExpr, n[1], 2)
  664. # Generating `let exc = (excType)(getCurrentException())`
  665. # -> getCurrentException()
  666. let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", newNodeI(nkEmpty, n.info)))
  667. # -> (excType)
  668. let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
  669. convNode[0] = PTransNode(newNodeI(nkEmpty, n.info))
  670. convNode[1] = excCall
  671. PNode(convNode).typ = excTypeNode.typ.toRef()
  672. # -> let exc = ...
  673. let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
  674. identDefs[0] = PTransNode(n[0][2])
  675. identDefs[1] = PTransNode(newNodeI(nkEmpty, n.info))
  676. identDefs[2] = convNode
  677. let letSection = newTransNode(nkLetSection, n[1].info, 1)
  678. letSection[0] = identDefs
  679. # Place the let statement and body of the 'except' branch into new stmtList.
  680. actions[0] = letSection
  681. actions[1] = transformSons(c, n[1])
  682. # Overwrite 'except' branch body with our stmtList.
  683. result[1] = actions
  684. # Replace the `Exception as foobar` with just `Exception`.
  685. result[0] = result[0][1]
  686. proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
  687. # symbols that expand to a complex constant (array, etc.) should not be
  688. # inlined, unless it's the empty array:
  689. result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
  690. cnst.len != 0
  691. proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
  692. result = n
  693. for i in 0 ..< n.safeLen:
  694. result.sons[i] = commonOptimizations(g, c, n.sons[i])
  695. var op = getMergeOp(n)
  696. if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
  697. result = newNodeIT(nkCall, n.info, n.typ)
  698. add(result, n.sons[0])
  699. var args = newNode(nkArgList)
  700. flattenTreeAux(args, n, op)
  701. var j = 0
  702. while j < sonsLen(args):
  703. var a = args.sons[j]
  704. inc(j)
  705. if isConstExpr(a):
  706. while j < sonsLen(args):
  707. let b = args.sons[j]
  708. if not isConstExpr(b): break
  709. a = evalOp(op.magic, result, a, b, nil, g)
  710. inc(j)
  711. add(result, a)
  712. if len(result) == 2: result = result[1]
  713. else:
  714. var cnst = getConstExpr(c, n, g)
  715. # we inline constants if they are not complex constants:
  716. if cnst != nil and not dontInlineConstant(n, cnst):
  717. result = cnst
  718. else:
  719. result = n
  720. proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNode =
  721. # This takes care of complicated signatures such as:
  722. # proc foo(a: int, b = a)
  723. # proc bar(a: int, b: int, c = a + b)
  724. #
  725. # The recursion may confuse you. It performs two duties:
  726. #
  727. # 1) extracting all referenced params from default expressions
  728. # into a let section preceeding the call
  729. #
  730. # 2) replacing the "references" within the default expression
  731. # with these extracted skLet symbols.
  732. #
  733. # The first duty is carried out directly in the code here, while the second
  734. # duty is activated by returning a non-nil value. The caller is responsible
  735. # for replacing the input to the function with the returned non-nil value.
  736. # (which is the hoisted symbol)
  737. if defExpr.kind == nkSym:
  738. if defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
  739. let paramPos = defExpr.sym.position + 1
  740. if call[paramPos].kind == nkSym and sfHoisted in call[paramPos].sym.flags:
  741. # Already hoisted, we still need to return it in order to replace the
  742. # placeholder expression in the default value.
  743. return call[paramPos]
  744. let hoistedVarSym = hoistExpr(letSection,
  745. call[paramPos],
  746. getIdent(c.graph.cache, genPrefix),
  747. c.transCon.owner).newSymNode
  748. call[paramPos] = hoistedVarSym
  749. return hoistedVarSym
  750. else:
  751. for i in 0..<defExpr.safeLen:
  752. let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
  753. if hoisted != nil: defExpr[i] = hoisted
  754. proc transform(c: PTransf, n: PNode): PTransNode =
  755. when false:
  756. var oldDeferAnchor: PNode
  757. if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
  758. nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
  759. nkBlockStmt, nkBlockExpr}:
  760. oldDeferAnchor = c.deferAnchor
  761. c.deferAnchor = n
  762. if n.typ != nil and tfHasAsgn in n.typ.flags:
  763. c.needsDestroyPass = true
  764. case n.kind
  765. of nkSym:
  766. result = transformSym(c, n)
  767. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
  768. # nothing to be done for leaves:
  769. result = PTransNode(n)
  770. of nkBracketExpr: result = transformArrayAccess(c, n)
  771. of procDefs:
  772. var s = n.sons[namePos].sym
  773. if n.typ != nil and s.typ.callConv == ccClosure:
  774. result = transformSym(c, n.sons[namePos])
  775. # use the same node as before if still a symbol:
  776. if result.PNode.kind == nkSym: result = PTransNode(n)
  777. else:
  778. result = PTransNode(n)
  779. of nkMacroDef:
  780. # XXX no proper closure support yet:
  781. when false:
  782. if n.sons[genericParamsPos].kind == nkEmpty:
  783. var s = n.sons[namePos].sym
  784. n.sons[bodyPos] = PNode(transform(c, s.getBody))
  785. if n.kind == nkMethodDef: methodDef(s, false)
  786. result = PTransNode(n)
  787. of nkForStmt:
  788. result = transformFor(c, n)
  789. of nkParForStmt:
  790. result = transformSons(c, n)
  791. of nkCaseStmt:
  792. result = transformCase(c, n)
  793. of nkWhileStmt: result = transformWhile(c, n)
  794. of nkBlockStmt, nkBlockExpr:
  795. result = transformBlock(c, n)
  796. of nkDefer:
  797. c.deferDetected = true
  798. result = transformSons(c, n)
  799. when false:
  800. let deferPart = newNodeI(nkFinally, n.info)
  801. deferPart.add n.sons[0]
  802. let tryStmt = newNodeI(nkTryStmt, n.info)
  803. if c.deferAnchor.isNil:
  804. tryStmt.add c.root
  805. c.root = tryStmt
  806. result = PTransNode(tryStmt)
  807. else:
  808. # modify the corresponding *action*, don't rely on nkStmtList:
  809. let L = c.deferAnchor.len-1
  810. tryStmt.add c.deferAnchor.sons[L]
  811. c.deferAnchor.sons[L] = tryStmt
  812. result = newTransNode(nkCommentStmt, n.info, 0)
  813. tryStmt.addSon(deferPart)
  814. # disable the original 'defer' statement:
  815. n.kind = nkEmpty
  816. of nkContinueStmt:
  817. result = PTransNode(newNodeI(nkBreakStmt, n.info))
  818. var labl = c.contSyms[c.contSyms.high]
  819. add(result, PTransNode(newSymNode(labl)))
  820. of nkBreakStmt: result = transformBreak(c, n)
  821. of nkCallKinds:
  822. result = transformCall(c, n)
  823. var call = result.PNode
  824. if nfDefaultRefsParam in call.flags:
  825. # We've found a default value that references another param.
  826. # See the notes in `hoistParamsUsedInDefault` for more details.
  827. var hoistedParams = newNodeI(nkLetSection, call.info, 0)
  828. for i in 1 ..< call.len:
  829. let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
  830. if hoisted != nil: call[i] = hoisted
  831. result = newTree(nkStmtListExpr, hoistedParams, call).PTransNode
  832. of nkAddr, nkHiddenAddr:
  833. result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
  834. of nkDerefExpr, nkHiddenDeref:
  835. result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
  836. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  837. result = transformConv(c, n)
  838. of nkDiscardStmt:
  839. result = PTransNode(n)
  840. if n.sons[0].kind != nkEmpty:
  841. result = transformSons(c, n)
  842. if isConstExpr(PNode(result).sons[0]):
  843. # ensure that e.g. discard "some comment" gets optimized away
  844. # completely:
  845. result = PTransNode(newNode(nkCommentStmt))
  846. of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
  847. nkExportStmt, nkExportExceptStmt:
  848. return n.PTransNode
  849. of nkConstSection:
  850. # do not replace ``const c = 3`` with ``const 3 = 3``
  851. return transformConstSection(c, n)
  852. of nkTypeSection, nkTypeOfExpr:
  853. # no need to transform type sections:
  854. return PTransNode(n)
  855. of nkVarSection, nkLetSection:
  856. if c.inlining > 0:
  857. # we need to copy the variables for multiple yield statements:
  858. result = transformVarSection(c, n)
  859. else:
  860. result = transformSons(c, n)
  861. of nkYieldStmt:
  862. if c.inlining > 0:
  863. result = transformYield(c, n)
  864. else:
  865. result = transformSons(c, n)
  866. of nkIdentDefs, nkConstDef:
  867. result = PTransNode(n)
  868. result[0] = transform(c, n[0])
  869. # Skip the second son since it only contains an unsemanticized copy of the
  870. # variable type used by docgen
  871. result[2] = transform(c, n[2])
  872. # XXX comment handling really sucks:
  873. if importantComments(c.graph.config):
  874. PNode(result).comment = n.comment
  875. of nkClosure:
  876. # it can happen that for-loop-inlining produced a fresh
  877. # set of variables, including some computed environment
  878. # (bug #2604). We need to patch this environment here too:
  879. let a = n[1]
  880. if a.kind == nkSym:
  881. n.sons[1] = transformSymAux(c, a)
  882. return PTransNode(n)
  883. of nkExceptBranch:
  884. result = transformExceptBranch(c, n)
  885. else:
  886. result = transformSons(c, n)
  887. when false:
  888. if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
  889. var cnst = getConstExpr(c.module, PNode(result), c.graph)
  890. # we inline constants if they are not complex constants:
  891. if cnst != nil and not dontInlineConstant(n, cnst):
  892. result = PTransNode(cnst) # do not miss an optimization
  893. proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  894. # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  895. # this step! We have to rely that the semantic pass transforms too errornous
  896. # nodes into an empty node.
  897. if nfTransf in n.flags: return n
  898. pushTransCon(c, newTransCon(owner))
  899. result = PNode(transform(c, n))
  900. popTransCon(c)
  901. incl(result.flags, nfTransf)
  902. proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
  903. new(result)
  904. result.contSyms = @[]
  905. result.breakSyms = @[]
  906. result.module = module
  907. result.graph = g
  908. proc flattenStmts(n: PNode) =
  909. var goOn = true
  910. while goOn:
  911. goOn = false
  912. var i = 0
  913. while i < n.len:
  914. let it = n[i]
  915. if it.kind in {nkStmtList, nkStmtListExpr}:
  916. n.sons[i..i] = it.sons[0..<it.len]
  917. goOn = true
  918. inc i
  919. proc liftDeferAux(n: PNode) =
  920. if n.kind in {nkStmtList, nkStmtListExpr}:
  921. flattenStmts(n)
  922. var goOn = true
  923. while goOn:
  924. goOn = false
  925. let last = n.len-1
  926. for i in 0..last:
  927. if n.sons[i].kind == nkDefer:
  928. let deferPart = newNodeI(nkFinally, n.sons[i].info)
  929. deferPart.add n.sons[i].sons[0]
  930. var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
  931. var body = newNodeI(n.kind, n.sons[i].info)
  932. if i < last:
  933. body.sons = n.sons[(i+1)..last]
  934. tryStmt.addSon(body)
  935. tryStmt.addSon(deferPart)
  936. n.sons[i] = tryStmt
  937. n.sons.setLen(i+1)
  938. n.typ = n.sons[i].typ
  939. goOn = true
  940. break
  941. for i in 0..n.safeLen-1:
  942. liftDeferAux(n.sons[i])
  943. template liftDefer(c, root) =
  944. if c.deferDetected:
  945. liftDeferAux(root)
  946. proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
  947. if nfTransf in n.flags or prc.kind in {skTemplate}:
  948. result = n
  949. else:
  950. var c = openTransf(g, module, "")
  951. result = liftLambdas(g, prc, n, c.tooEarly)
  952. #result = n
  953. result = processTransf(c, result, prc)
  954. liftDefer(c, result)
  955. #result = liftLambdas(prc, result)
  956. when useEffectSystem: trackProc(g, prc, result)
  957. result = liftLocalsIfRequested(prc, result, g.cache, g.config)
  958. if c.needsDestroyPass: #and newDestructors:
  959. result = injectDestructorCalls(g, prc, result)
  960. if prc.isIterator:
  961. result = g.transformClosureIterator(prc, result)
  962. incl(result.flags, nfTransf)
  963. #if prc.name.s == "testbody":
  964. # echo renderTree(result)
  965. proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  966. if nfTransf in n.flags:
  967. result = n
  968. else:
  969. var c = openTransf(g, module, "")
  970. result = processTransf(c, n, module)
  971. liftDefer(c, result)
  972. #result = liftLambdasForTopLevel(module, result)
  973. when useEffectSystem: trackTopLevelStmt(g, module, result)
  974. #if n.info ?? "temp.nim":
  975. # echo renderTree(result, {renderIds})
  976. if c.needsDestroyPass:
  977. result = injectDestructorCalls(g, module, result)
  978. incl(result.flags, nfTransf)
  979. proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  980. if nfTransf in n.flags:
  981. result = n
  982. else:
  983. var c = openTransf(g, module, "")
  984. result = processTransf(c, n, module)
  985. liftDefer(c, result)
  986. # expressions are not to be injected with destructor calls as that
  987. # the list of top level statements needs to be collected before.
  988. if c.needsDestroyPass:
  989. result = injectDestructorCalls(g, module, result)
  990. incl(result.flags, nfTransf)