transf.nim 42 KB

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