transf.nim 40 KB

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