transf.nim 39 KB

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