transf.nim 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  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. if result.len > 0:
  331. var changeNode = PNode(result[0])
  332. changeNode.info = c.transCon.forStmt.info
  333. for i, child in changeNode:
  334. child.info = changeNode.info
  335. proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
  336. result = transformSons(c, n)
  337. if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
  338. var n = result.PNode
  339. case n.sons[0].kind
  340. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  341. var m = n.sons[0].sons[0]
  342. if m.kind == a or m.kind == b:
  343. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  344. n.sons[0].sons[0] = m.sons[0]
  345. result = PTransNode(n.sons[0])
  346. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  347. PNode(result).typ = n.typ
  348. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  349. PNode(result).typ = toVar(PNode(result).typ)
  350. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  351. var m = n.sons[0].sons[1]
  352. if m.kind == a or m.kind == b:
  353. # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
  354. n.sons[0].sons[1] = m.sons[0]
  355. result = PTransNode(n.sons[0])
  356. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  357. PNode(result).typ = n.typ
  358. elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
  359. PNode(result).typ = toVar(PNode(result).typ)
  360. else:
  361. if n.sons[0].kind == a or n.sons[0].kind == b:
  362. # addr ( deref ( x )) --> x
  363. result = PTransNode(n.sons[0].sons[0])
  364. if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
  365. PNode(result).typ = n.typ
  366. proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
  367. ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  368. ## a closure.
  369. # we cannot generate a proper thunk here for GC-safety reasons
  370. # (see internal documentation):
  371. if c.graph.config.cmd == cmdCompileToJS: return prc
  372. result = newNodeIT(nkClosure, prc.info, dest)
  373. var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  374. conv.add(newNodeI(nkEmpty, prc.info))
  375. conv.add(prc)
  376. if prc.kind == nkClosure:
  377. internalError(c.graph.config, prc.info, "closure to closure created")
  378. result.add(conv)
  379. result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
  380. proc transformConv(c: PTransf, n: PNode): PTransNode =
  381. # numeric types need range checks:
  382. var dest = skipTypes(n.typ, abstractVarRange)
  383. var source = skipTypes(n.sons[1].typ, abstractVarRange)
  384. case dest.kind
  385. of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
  386. # we don't include uint and uint64 here as these are no ordinal types ;-)
  387. if not isOrdinalType(source):
  388. # float -> int conversions. ugh.
  389. result = transformSons(c, n)
  390. elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n.sons[1].typ) and
  391. lastOrd(c.graph.config, n.sons[1].typ) <= lastOrd(c.graph.config, n.typ):
  392. # BUGFIX: simply leave n as it is; we need a nkConv node,
  393. # but no range check:
  394. result = transformSons(c, n)
  395. else:
  396. # generate a range check:
  397. if dest.kind == tyInt64 or source.kind == tyInt64:
  398. result = newTransNode(nkChckRange64, n, 3)
  399. else:
  400. result = newTransNode(nkChckRange, n, 3)
  401. dest = skipTypes(n.typ, abstractVar)
  402. result[0] = transform(c, n.sons[1])
  403. result[1] = newIntTypeNode(nkIntLit, firstOrd(c.graph.config, dest), dest).PTransNode
  404. result[2] = newIntTypeNode(nkIntLit, lastOrd(c.graph.config, dest), dest).PTransNode
  405. of tyFloat..tyFloat128:
  406. # XXX int64 -> float conversion?
  407. if skipTypes(n.typ, abstractVar).kind == tyRange:
  408. result = newTransNode(nkChckRangeF, n, 3)
  409. dest = skipTypes(n.typ, abstractVar)
  410. result[0] = transform(c, n.sons[1])
  411. result[1] = copyTree(dest.n.sons[0]).PTransNode
  412. result[2] = copyTree(dest.n.sons[1]).PTransNode
  413. else:
  414. result = transformSons(c, n)
  415. of tyOpenArray, tyVarargs:
  416. result = transform(c, n.sons[1])
  417. PNode(result).typ = takeType(n.typ, n.sons[1].typ)
  418. #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
  419. # " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
  420. of tyCString:
  421. if source.kind == tyString:
  422. result = newTransNode(nkStringToCString, n, 1)
  423. result[0] = transform(c, n.sons[1])
  424. else:
  425. result = transformSons(c, n)
  426. of tyString:
  427. if source.kind == tyCString:
  428. result = newTransNode(nkCStringToString, n, 1)
  429. result[0] = transform(c, n.sons[1])
  430. else:
  431. result = transformSons(c, n)
  432. of tyRef, tyPtr:
  433. dest = skipTypes(dest, abstractPtrs)
  434. source = skipTypes(source, abstractPtrs)
  435. if source.kind == tyObject:
  436. var diff = inheritanceDiff(dest, source)
  437. if diff < 0:
  438. result = newTransNode(nkObjUpConv, n, 1)
  439. result[0] = transform(c, n.sons[1])
  440. elif diff > 0 and diff != high(int):
  441. result = newTransNode(nkObjDownConv, n, 1)
  442. result[0] = transform(c, n.sons[1])
  443. else:
  444. result = transform(c, n.sons[1])
  445. else:
  446. result = transformSons(c, n)
  447. of tyObject:
  448. var diff = inheritanceDiff(dest, source)
  449. if diff < 0:
  450. result = newTransNode(nkObjUpConv, n, 1)
  451. result[0] = transform(c, n.sons[1])
  452. elif diff > 0 and diff != high(int):
  453. result = newTransNode(nkObjDownConv, n, 1)
  454. result[0] = transform(c, n.sons[1])
  455. else:
  456. result = transform(c, n.sons[1])
  457. of tyGenericParam, tyOrdinal:
  458. result = transform(c, n.sons[1])
  459. # happens sometimes for generated assignments, etc.
  460. of tyProc:
  461. result = transformSons(c, n)
  462. if dest.callConv == ccClosure and source.callConv == ccDefault:
  463. result = generateThunk(c, result[1].PNode, dest).PTransNode
  464. else:
  465. result = transformSons(c, n)
  466. type
  467. TPutArgInto = enum
  468. paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
  469. proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  470. # This analyses how to treat the mapping "formal <-> arg" in an
  471. # inline context.
  472. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
  473. if arg.kind == nkStmtListExpr:
  474. return paComplexOpenarray
  475. return paDirectMapping # XXX really correct?
  476. # what if ``arg`` has side-effects?
  477. case arg.kind
  478. of nkEmpty..nkNilLit:
  479. result = paDirectMapping
  480. of nkPar, nkTupleConstr, nkCurly, nkBracket:
  481. result = paFastAsgn
  482. for i in countup(0, sonsLen(arg) - 1):
  483. if putArgInto(arg.sons[i], formal) != paDirectMapping: return
  484. result = paDirectMapping
  485. else:
  486. if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
  487. else: result = paFastAsgn
  488. proc findWrongOwners(c: PTransf, n: PNode) =
  489. if n.kind == nkVarSection:
  490. let x = n.sons[0].sons[0]
  491. if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
  492. internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
  493. x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  494. else:
  495. for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
  496. proc transformFor(c: PTransf, n: PNode): PTransNode =
  497. # generate access statements for the parameters (unless they are constant)
  498. # put mapping from formal parameters to actual parameters
  499. if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
  500. var length = sonsLen(n)
  501. var call = n.sons[length - 2]
  502. let labl = newLabel(c, n)
  503. result = newTransNode(nkBlockStmt, n.info, 2)
  504. result[0] = newSymNode(labl).PTransNode
  505. if call.typ.isNil:
  506. # see bug #3051
  507. result[1] = newNode(nkEmpty).PTransNode
  508. return result
  509. c.breakSyms.add(labl)
  510. if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
  511. call.sons[0].typ.callConv == ccClosure:
  512. result[1] = n.PTransNode
  513. result[1][^1] = transformLoopBody(c, n[^1])
  514. result[1][^2] = transform(c, n[^2])
  515. result[1] = lambdalifting.liftForLoop(c.graph, result[1].PNode, getCurrOwner(c)).PTransNode
  516. discard c.breakSyms.pop
  517. return result
  518. #echo "transforming: ", renderTree(n)
  519. var stmtList = newTransNode(nkStmtList, n.info, 0)
  520. result[1] = stmtList
  521. var loopBody = transformLoopBody(c, n.sons[length-1])
  522. discard c.breakSyms.pop
  523. var v = newNodeI(nkVarSection, n.info)
  524. for i in countup(0, length - 3):
  525. addVar(v, copyTree(n.sons[i])) # declare new vars
  526. add(stmtList, v.PTransNode)
  527. # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  528. # iterator!
  529. let iter = call.sons[0].sym
  530. var newC = newTransCon(getCurrOwner(c))
  531. newC.forStmt = n
  532. newC.forLoopBody = loopBody
  533. # this can fail for 'nimsuggest' and 'check':
  534. if iter.kind != skIterator: return result
  535. # generate access statements for the parameters (unless they are constant)
  536. pushTransCon(c, newC)
  537. for i in countup(1, sonsLen(call) - 1):
  538. var arg = transform(c, call.sons[i]).PNode
  539. let ff = skipTypes(iter.typ, abstractInst)
  540. # can happen for 'nim check':
  541. if i >= ff.n.len: return result
  542. var formal = ff.n.sons[i].sym
  543. case putArgInto(arg, formal.typ)
  544. of paDirectMapping:
  545. idNodeTablePut(newC.mapping, formal, arg)
  546. of paFastAsgn:
  547. # generate a temporary and produce an assignment statement:
  548. var temp = newTemp(c, formal.typ, formal.info)
  549. addVar(v, temp)
  550. add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
  551. idNodeTablePut(newC.mapping, formal, temp)
  552. of paVarAsgn:
  553. assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
  554. idNodeTablePut(newC.mapping, formal, arg)
  555. # XXX BUG still not correct if the arg has a side effect!
  556. of paComplexOpenarray:
  557. let typ = newType(tySequence, formal.owner)
  558. addSonSkipIntLit(typ, formal.typ.sons[0])
  559. var temp = newTemp(c, typ, formal.info)
  560. addVar(v, temp)
  561. add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
  562. idNodeTablePut(newC.mapping, formal, temp)
  563. let body = transformBody(c.graph, iter, true, c.noDestructors)
  564. pushInfoContext(c.graph.config, n.info)
  565. inc(c.inlining)
  566. add(stmtList, transform(c, body))
  567. #findWrongOwners(c, stmtList.pnode)
  568. dec(c.inlining)
  569. popInfoContext(c.graph.config)
  570. popTransCon(c)
  571. # echo "transformed: ", stmtList.PNode.renderTree
  572. proc transformCase(c: PTransf, n: PNode): PTransNode =
  573. # removes `elif` branches of a case stmt
  574. # adds ``else: nil`` if needed for the code generator
  575. result = newTransNode(nkCaseStmt, n, 0)
  576. var ifs = PTransNode(nil)
  577. for i in 0 .. sonsLen(n)-1:
  578. var it = n.sons[i]
  579. var e = transform(c, it)
  580. case it.kind
  581. of nkElifBranch:
  582. if ifs.PNode == nil:
  583. # Generate the right node depending on whether `n` is used as a stmt or
  584. # as an expr
  585. let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
  586. ifs = newTransNode(kind, it.info, 0)
  587. ifs.PNode.typ = n.typ
  588. ifs.add(e)
  589. of nkElse:
  590. if ifs.PNode == nil: result.add(e)
  591. else: ifs.add(e)
  592. else:
  593. result.add(e)
  594. if ifs.PNode != nil:
  595. var elseBranch = newTransNode(nkElse, n.info, 1)
  596. elseBranch[0] = ifs
  597. result.add(elseBranch)
  598. elif result.PNode.lastSon.kind != nkElse and not (
  599. skipTypes(n.sons[0].typ, abstractVarRange).kind in
  600. {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
  601. # fix a stupid code gen bug by normalizing:
  602. var elseBranch = newTransNode(nkElse, n.info, 1)
  603. elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
  604. add(result, elseBranch)
  605. proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
  606. # XXX this is really bad; transf should use a proper AST visitor
  607. if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
  608. result = n.PTransNode
  609. else:
  610. result = newTransNode(n)
  611. for i in 0 ..< n.len:
  612. result[i] = transform(c, skipConv(n.sons[i]))
  613. proc getMergeOp(n: PNode): PSym =
  614. case n.kind
  615. of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
  616. nkCallStrLit:
  617. if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
  618. result = n.sons[0].sym
  619. else: discard
  620. proc flattenTreeAux(d, a: PNode, op: PSym) =
  621. let op2 = getMergeOp(a)
  622. if op2 != nil and
  623. (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
  624. for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
  625. else:
  626. addSon(d, copyTree(a))
  627. proc flattenTree(root: PNode): PNode =
  628. let op = getMergeOp(root)
  629. if op != nil:
  630. result = copyNode(root)
  631. addSon(result, copyTree(root.sons[0]))
  632. flattenTreeAux(result, root, op)
  633. else:
  634. result = root
  635. proc transformCall(c: PTransf, n: PNode): PTransNode =
  636. var n = flattenTree(n)
  637. let op = getMergeOp(n)
  638. let magic = getMagic(n)
  639. if op != nil and op.magic != mNone and n.len >= 3:
  640. result = newTransNode(nkCall, n, 0)
  641. add(result, transform(c, n.sons[0]))
  642. var j = 1
  643. while j < sonsLen(n):
  644. var a = transform(c, n.sons[j]).PNode
  645. inc(j)
  646. if isConstExpr(a):
  647. while (j < sonsLen(n)):
  648. let b = transform(c, n.sons[j]).PNode
  649. if not isConstExpr(b): break
  650. a = evalOp(op.magic, n, a, b, nil, c.graph)
  651. inc(j)
  652. add(result, a.PTransNode)
  653. if len(result) == 2: result = result[1]
  654. elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
  655. # for bindSym(myconst) we MUST NOT perform constant folding:
  656. result = n.PTransNode
  657. elif magic == mProcCall:
  658. # but do not change to its dispatcher:
  659. result = transformSons(c, n[1])
  660. else:
  661. let s = transformSons(c, n).PNode
  662. # bugfix: check after 'transformSons' if it's still a method call:
  663. # use the dispatcher for the call:
  664. if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
  665. when false:
  666. let t = lastSon(s.sons[0].sym.ast)
  667. if t.kind != nkSym or sfDispatcher notin t.sym.flags:
  668. methodDef(s.sons[0].sym, false)
  669. result = methodCall(s, c.graph.config).PTransNode
  670. else:
  671. result = s.PTransNode
  672. proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
  673. result = transformSons(c, n)
  674. if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
  675. let excTypeNode = n[0][1]
  676. let actions = newTransNode(nkStmtListExpr, n[1], 2)
  677. # Generating `let exc = (excType)(getCurrentException())`
  678. # -> getCurrentException()
  679. let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException"))
  680. # -> (excType)
  681. let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
  682. convNode[0] = PTransNode(newNodeI(nkEmpty, n.info))
  683. convNode[1] = excCall
  684. PNode(convNode).typ = excTypeNode.typ.toRef()
  685. # -> let exc = ...
  686. let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
  687. identDefs[0] = PTransNode(n[0][2])
  688. identDefs[1] = PTransNode(newNodeI(nkEmpty, n.info))
  689. identDefs[2] = convNode
  690. let letSection = newTransNode(nkLetSection, n[1].info, 1)
  691. letSection[0] = identDefs
  692. # Place the let statement and body of the 'except' branch into new stmtList.
  693. actions[0] = letSection
  694. actions[1] = transformSons(c, n[1])
  695. # Overwrite 'except' branch body with our stmtList.
  696. result[1] = actions
  697. # Replace the `Exception as foobar` with just `Exception`.
  698. result[0] = result[0][1]
  699. proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
  700. # symbols that expand to a complex constant (array, etc.) should not be
  701. # inlined, unless it's the empty array:
  702. result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
  703. cnst.len != 0
  704. proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
  705. result = n
  706. for i in 0 ..< n.safeLen:
  707. result.sons[i] = commonOptimizations(g, c, n.sons[i])
  708. var op = getMergeOp(n)
  709. if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
  710. result = newNodeIT(nkCall, n.info, n.typ)
  711. add(result, n.sons[0])
  712. var args = newNode(nkArgList)
  713. flattenTreeAux(args, n, op)
  714. var j = 0
  715. while j < sonsLen(args):
  716. var a = args.sons[j]
  717. inc(j)
  718. if isConstExpr(a):
  719. while j < sonsLen(args):
  720. let b = args.sons[j]
  721. if not isConstExpr(b): break
  722. a = evalOp(op.magic, result, a, b, nil, g)
  723. inc(j)
  724. add(result, a)
  725. if len(result) == 2: result = result[1]
  726. else:
  727. var cnst = getConstExpr(c, n, g)
  728. # we inline constants if they are not complex constants:
  729. if cnst != nil and not dontInlineConstant(n, cnst):
  730. result = cnst
  731. else:
  732. result = n
  733. proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNode =
  734. # This takes care of complicated signatures such as:
  735. # proc foo(a: int, b = a)
  736. # proc bar(a: int, b: int, c = a + b)
  737. #
  738. # The recursion may confuse you. It performs two duties:
  739. #
  740. # 1) extracting all referenced params from default expressions
  741. # into a let section preceeding the call
  742. #
  743. # 2) replacing the "references" within the default expression
  744. # with these extracted skLet symbols.
  745. #
  746. # The first duty is carried out directly in the code here, while the second
  747. # duty is activated by returning a non-nil value. The caller is responsible
  748. # for replacing the input to the function with the returned non-nil value.
  749. # (which is the hoisted symbol)
  750. if defExpr.kind == nkSym:
  751. if defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
  752. let paramPos = defExpr.sym.position + 1
  753. if call[paramPos].kind == nkSym and sfHoisted in call[paramPos].sym.flags:
  754. # Already hoisted, we still need to return it in order to replace the
  755. # placeholder expression in the default value.
  756. return call[paramPos]
  757. let hoistedVarSym = hoistExpr(letSection,
  758. call[paramPos],
  759. getIdent(c.graph.cache, genPrefix),
  760. c.transCon.owner).newSymNode
  761. call[paramPos] = hoistedVarSym
  762. return hoistedVarSym
  763. else:
  764. for i in 0..<defExpr.safeLen:
  765. let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
  766. if hoisted != nil: defExpr[i] = hoisted
  767. proc transform(c: PTransf, n: PNode): PTransNode =
  768. when false:
  769. var oldDeferAnchor: PNode
  770. if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
  771. nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
  772. nkBlockStmt, nkBlockExpr}:
  773. oldDeferAnchor = c.deferAnchor
  774. c.deferAnchor = n
  775. if n.typ != nil and tfHasAsgn in n.typ.flags:
  776. c.needsDestroyPass = true
  777. case n.kind
  778. of nkSym:
  779. result = transformSym(c, n)
  780. of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
  781. # nothing to be done for leaves:
  782. result = PTransNode(n)
  783. of nkBracketExpr: result = transformArrayAccess(c, n)
  784. of procDefs:
  785. var s = n.sons[namePos].sym
  786. if n.typ != nil and s.typ.callConv == ccClosure:
  787. result = transformSym(c, n.sons[namePos])
  788. # use the same node as before if still a symbol:
  789. if result.PNode.kind == nkSym: result = PTransNode(n)
  790. else:
  791. result = PTransNode(n)
  792. of nkMacroDef:
  793. # XXX no proper closure support yet:
  794. when false:
  795. if n.sons[genericParamsPos].kind == nkEmpty:
  796. var s = n.sons[namePos].sym
  797. n.sons[bodyPos] = PNode(transform(c, s.getBody))
  798. if n.kind == nkMethodDef: methodDef(s, false)
  799. result = PTransNode(n)
  800. of nkForStmt:
  801. result = transformFor(c, n)
  802. of nkParForStmt:
  803. result = transformSons(c, n)
  804. of nkCaseStmt:
  805. result = transformCase(c, n)
  806. of nkWhileStmt: result = transformWhile(c, n)
  807. of nkBlockStmt, nkBlockExpr:
  808. result = transformBlock(c, n)
  809. of nkDefer:
  810. c.deferDetected = true
  811. result = transformSons(c, n)
  812. when false:
  813. let deferPart = newNodeI(nkFinally, n.info)
  814. deferPart.add n.sons[0]
  815. let tryStmt = newNodeI(nkTryStmt, n.info)
  816. if c.deferAnchor.isNil:
  817. tryStmt.add c.root
  818. c.root = tryStmt
  819. result = PTransNode(tryStmt)
  820. else:
  821. # modify the corresponding *action*, don't rely on nkStmtList:
  822. let L = c.deferAnchor.len-1
  823. tryStmt.add c.deferAnchor.sons[L]
  824. c.deferAnchor.sons[L] = tryStmt
  825. result = newTransNode(nkCommentStmt, n.info, 0)
  826. tryStmt.addSon(deferPart)
  827. # disable the original 'defer' statement:
  828. n.kind = nkEmpty
  829. of nkContinueStmt:
  830. result = PTransNode(newNodeI(nkBreakStmt, n.info))
  831. var labl = c.contSyms[c.contSyms.high]
  832. add(result, PTransNode(newSymNode(labl)))
  833. of nkBreakStmt: result = transformBreak(c, n)
  834. of nkCallKinds:
  835. result = transformCall(c, n)
  836. var call = result.PNode
  837. if nfDefaultRefsParam in call.flags:
  838. # We've found a default value that references another param.
  839. # See the notes in `hoistParamsUsedInDefault` for more details.
  840. var hoistedParams = newNodeI(nkLetSection, call.info, 0)
  841. for i in 1 ..< call.len:
  842. let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
  843. if hoisted != nil: call[i] = hoisted
  844. result = newTree(nkStmtListExpr, hoistedParams, call).PTransNode
  845. of nkAddr, nkHiddenAddr:
  846. result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
  847. of nkDerefExpr, nkHiddenDeref:
  848. result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
  849. of nkHiddenStdConv, nkHiddenSubConv, nkConv:
  850. result = transformConv(c, n)
  851. of nkDiscardStmt:
  852. result = PTransNode(n)
  853. if n.sons[0].kind != nkEmpty:
  854. result = transformSons(c, n)
  855. if isConstExpr(PNode(result).sons[0]):
  856. # ensure that e.g. discard "some comment" gets optimized away
  857. # completely:
  858. result = PTransNode(newNode(nkCommentStmt))
  859. of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
  860. nkExportStmt, nkExportExceptStmt:
  861. return n.PTransNode
  862. of nkConstSection:
  863. # do not replace ``const c = 3`` with ``const 3 = 3``
  864. return transformConstSection(c, n)
  865. of nkTypeSection, nkTypeOfExpr:
  866. # no need to transform type sections:
  867. return PTransNode(n)
  868. of nkVarSection, nkLetSection:
  869. if c.inlining > 0:
  870. # we need to copy the variables for multiple yield statements:
  871. result = transformVarSection(c, n)
  872. else:
  873. result = transformSons(c, n)
  874. of nkYieldStmt:
  875. if c.inlining > 0:
  876. result = transformYield(c, n)
  877. else:
  878. result = transformSons(c, n)
  879. of nkIdentDefs, nkConstDef:
  880. result = PTransNode(n)
  881. result[0] = transform(c, n[0])
  882. # Skip the second son since it only contains an unsemanticized copy of the
  883. # variable type used by docgen
  884. result[2] = transform(c, n[2])
  885. # XXX comment handling really sucks:
  886. if importantComments(c.graph.config):
  887. PNode(result).comment = n.comment
  888. of nkClosure:
  889. # it can happen that for-loop-inlining produced a fresh
  890. # set of variables, including some computed environment
  891. # (bug #2604). We need to patch this environment here too:
  892. let a = n[1]
  893. if a.kind == nkSym:
  894. n.sons[1] = transformSymAux(c, a)
  895. return PTransNode(n)
  896. of nkExceptBranch:
  897. result = transformExceptBranch(c, n)
  898. else:
  899. result = transformSons(c, n)
  900. when false:
  901. if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
  902. var cnst = getConstExpr(c.module, PNode(result), c.graph)
  903. # we inline constants if they are not complex constants:
  904. if cnst != nil and not dontInlineConstant(n, cnst):
  905. result = PTransNode(cnst) # do not miss an optimization
  906. proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  907. # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  908. # this step! We have to rely that the semantic pass transforms too errornous
  909. # nodes into an empty node.
  910. if nfTransf in n.flags: return n
  911. pushTransCon(c, newTransCon(owner))
  912. result = PNode(transform(c, n))
  913. popTransCon(c)
  914. incl(result.flags, nfTransf)
  915. proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
  916. new(result)
  917. result.contSyms = @[]
  918. result.breakSyms = @[]
  919. result.module = module
  920. result.graph = g
  921. proc flattenStmts(n: PNode) =
  922. var goOn = true
  923. while goOn:
  924. goOn = false
  925. var i = 0
  926. while i < n.len:
  927. let it = n[i]
  928. if it.kind in {nkStmtList, nkStmtListExpr}:
  929. n.sons[i..i] = it.sons[0..<it.len]
  930. goOn = true
  931. inc i
  932. proc liftDeferAux(n: PNode) =
  933. if n.kind in {nkStmtList, nkStmtListExpr}:
  934. flattenStmts(n)
  935. var goOn = true
  936. while goOn:
  937. goOn = false
  938. let last = n.len-1
  939. for i in 0..last:
  940. if n.sons[i].kind == nkDefer:
  941. let deferPart = newNodeI(nkFinally, n.sons[i].info)
  942. deferPart.add n.sons[i].sons[0]
  943. var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
  944. var body = newNodeI(n.kind, n.sons[i].info)
  945. if i < last:
  946. body.sons = n.sons[(i+1)..last]
  947. tryStmt.addSon(body)
  948. tryStmt.addSon(deferPart)
  949. n.sons[i] = tryStmt
  950. n.sons.setLen(i+1)
  951. n.typ = n.sons[i].typ
  952. goOn = true
  953. break
  954. for i in 0..n.safeLen-1:
  955. liftDeferAux(n.sons[i])
  956. template liftDefer(c, root) =
  957. if c.deferDetected:
  958. liftDeferAux(root)
  959. proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
  960. noDestructors = false): PNode =
  961. assert prc.kind in routineKinds
  962. if prc.transformedBody != nil:
  963. result = prc.transformedBody
  964. elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
  965. result = prc.ast[bodyPos]
  966. else:
  967. prc.transformedBody = newNode(nkEmpty) # protects from recursion
  968. var c = openTransf(g, prc.getModule, "")
  969. c.noDestructors = noDestructors
  970. result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
  971. result = processTransf(c, result, prc)
  972. liftDefer(c, result)
  973. result = liftLocalsIfRequested(prc, result, g.cache, g.config)
  974. if c.needsDestroyPass and not noDestructors:
  975. result = injectDestructorCalls(g, prc, result)
  976. if prc.isIterator:
  977. result = g.transformClosureIterator(prc, result)
  978. incl(result.flags, nfTransf)
  979. let cache = cache or prc.typ.callConv == ccInline
  980. if cache:
  981. # genProc for inline procs will be called multiple times from diffrent modules,
  982. # it is important to transform exactly once to get sym ids and locations right
  983. prc.transformedBody = result
  984. else:
  985. prc.transformedBody = nil
  986. proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  987. if nfTransf in n.flags:
  988. result = n
  989. else:
  990. var c = openTransf(g, module, "")
  991. result = processTransf(c, n, module)
  992. liftDefer(c, result)
  993. #result = liftLambdasForTopLevel(module, result)
  994. if c.needsDestroyPass:
  995. result = injectDestructorCalls(g, module, result)
  996. incl(result.flags, nfTransf)
  997. proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
  998. noDestructors = false): PNode =
  999. if nfTransf in n.flags:
  1000. result = n
  1001. else:
  1002. var c = openTransf(g, module, "")
  1003. result = processTransf(c, n, module)
  1004. liftDefer(c, result)
  1005. # expressions are not to be injected with destructor calls as that
  1006. # the list of top level statements needs to be collected before.
  1007. if c.needsDestroyPass and not noDestructors:
  1008. result = injectDestructorCalls(g, module, result)
  1009. incl(result.flags, nfTransf)