summary refs log blame commit diff stats
path: root/compiler/transf.nim
blob: 5922ca5956a99aceb4156c39f4fa51949f5dfd4b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

 
                            
                                         









                                                                         
                             
                                                         
                                 
                                               
                                                     
 
      
                                     
                                                     
                        
                         
 
                                                                  


                                  
    

                                                           


                                                             
                                                    
                                                                        

                                                                          
                                            
 
                                         


                                                                            
                                                             
                                                                         
                                 
                      

                              

                                               
 
                                                   
                                                

                              
            
 
                                            
                                                


                                        
                    
            
 
                                          
                     

                                 
                      
 
                                             


                     
                              
                                                                      

                              
                                     

                                                 
 
                                                              
                                                                                   
                                                               


                                         
                                                      

                          
 
                                           
 
                                                 
                          

                                  
 


                                                                            
                
 
                                                   

                                                  
                              
                                             

                             
                                                           
                                                                              
                                                                         
                                                 

                                                                         
                       
              
                     
                                                    
                                 
                 
                                                                                              
                                 












                                                                          
       
         
                  
                                              





                                                                         

                
 

                                                
 


                                           
                                                      





                                     
                                                       
                          

                     
                                
                    
                                
                             
                                                   

                                                        
                                                        
                                             
                                           




                                               

                        


                                                                            

                               
                                                                                     

                                                       
                               


                                                          

                                       


                                           

                      

                                                         

                            

                       
                                  
                      

                                                                                                 

                               
                                                                         
 
                      
 
                                  
             
                                                                     
                                  
       

                                       
 
                                           
                                                        
                                                  
 
                                                  
                


                                                                  
       
          

                                                                    

                      


                              
                              
 
                                                     
                                                             
                                            
 


                                                                          
                    

                             

                                                 
                                
                               
                            
       
                            
 
                                                  





                                                 
                                
 
                              


                                          

                           
 
                                                  
                              
                                                  
                                            
                                
 
                                                         
             
           
                               
                                                 
                                    
              
                                
                                      





                                                              

                                  

                            

                                                
 
                                                 












                                                                             

                                            





                                                                             
                              








                                                

                                                  


                                                                            
                 






                                                             
                                              
              

                                                                         
                                                                              
                                 
                   
                                        


                                              
                                                    
                                                   

                                                                 
                                        
             
                                         
                                   
                                      
         

                                                                 

                                              
                                                             
                                    
       

                                                

                                                             
                                    
         
                                     
                               
                                  
 


                                
                                      
       
                                               
                                                                
                    
                              


                                             
 
                                                                       
                              
                                                                                     

                
                                                                          
                   
                                  
                                                     

                    
                                                          
                          
                                                         
                                                                          
                                              
                   
                                  
                                                     

                    
                                                          
                          
                                                         
                                                                          
       
                                        
                                 
                      
                                                          
                          
 
                                                                




                                                                    
                                                    
                                               
                                                       
                                       
               
                           
                                                                         
                  
                                                                                 
 
                                                 
                                    
                                               
                                                    
                
                                                       
                                                                             
                                 
                                      
                                  

                                                                                  

                                                               
                                  
         
                               
                                                        
                                                  
           
                                                
                                          


                                                                      

                                    
                                                     
                                               
                                          


                                     

                                  
                            
                               
                                 


                                                                       

                               
                                                    
                                    

                                  

                                
                                                    
                                    

                                  
                  

                                            
                               
                                              
                  
                                                
                                      
                                          
                                                  
                                      
           
                                   

                                  
              
                                            
                
                                              
                                    
                                        
                                                
                                    
         
                                 
                               
                               
                                                       

                                
                                                                   
                                                
       
                                


                    

                                                          
 
                                                         

                                                                 
                                                      
                                                                      


                               


                                      

                                                                 
               
                       
                            


                                                                 
                         
                                                       





                                                          
                                                  
                         
                            
       
                                                                                  
                             
 

                                            
                   
                                                          
                                                                         

                                                          
                                                    
 















                                                             
                                                

                                                                            
                                                                               
 
                  

                           
                                               
                              

                    
                                
                 
                       


                                                                

                                               
                                                                              

                           
 
                                       
                                                    
                      
 
                                            
 

                         

                        
                                        
                         
                               
                              

                                                       

                                                          

                                                  
 
 

                                                                             
                                         
                  
                             

                                               
                                                                            
                       
                        
                                   


                                              
                            

                                        
                       
                                               
                                             
                        


                                                                                          
                                                                                

                                                             
                                                                 
                                           
                     
                                                         
                                                
                 
                                                                 
                                               
                                                               
                          

                                                 
                     
                                                         

                                                
                                               
                                         
                 
                                  
                                     
                 
                                
                
                                             
 
                                                 

                                                       
                                         

                      


                            
                    



                                                                               
                       

                
                                  


                      
                


                                                    

                                                   
                                                            
                                               

                                                     
                          
 
                                                        
                                                                  

                                                    

                            

                                              

                                 
             

                                                                       

                                                           
               
 
                                            
                         
                   
                                                                       
                                                   
       
                     

                                      
                           
               
                           
                                
                                    
       
                 
 
                                                 
                        

                         
                                                    
                                       
                                  
             

                                
            
                        

                                    
                                      
                                                     
                

                                          

                                       

                                                                      
                                                        
                                                                
              


                                          

                               
       
                               

                                                                      
                                                        
                 
                                     
                                                             

                                            
         
                
 
                                                         
                                                                               
                             
                                                       
                                                             
                              
                                                                 
                  
                                                              
                                           
                         
                                          
                      
                                                           

                                            



                                                             
                                                                                
                           
                                   
                                                       
                                                       
                                                              



                                     
 
                                                                     
            

                                               
                        
                                                          
                                             
                    


                                 

                       

                        

                           
                                      
                                                    
                

                                          
       
                                    





                                                            
                                             






                                                                        
             
           
                               
                                                              
                                    
              
                                                       
              
                          
                                                    
                                          
                                                      
                                         
         
                
                
                                        
               


                                             
                                                     
              
               
                               
                  
                                









                                                 
                        



                                               
                        

                                                                      

                                     
                                                       
                           
                                               
                      
                    
                                          
                                          
                                
                                               
                 
                                
                          
                                                                 
                                
                                                           
                                              
                                
                   

                            
                                  
                                

                                                                     
                                       

                                                              
            
                    
                                                         
                                      
                                 
                                         
            
                                
                      


                                                                    
                                  
                 

                                   
         
                                  

                                
                             
              



                                                                              
                                        
                                         
                                





                                                              

                                  

                                        
       
                                

                                                            
 


                                                                           
                                          

                                                 
                                                      

                                                            
                                                 
 
                                                              


                                                                              
                                  
                                     
                          
                
                              
 
                                                                          



                        
                  
 



                             

                    



                                                 
           








                                            


                                                        

                                                              

                                           


                               
                            
                             


                          
                      




                             
                                                                    





                                                                      
       

                                                                    
                                                              
                                          
                        
                                                                  
 
                      
                                                      
 
                                
 
                                             
                                                                                      



                                                                                    
 


                                                              
                                                                    


                         
                                     
                                        
                        
                                                    
                                
 
                                                                    
                         

              
                                     
                                        
                        

                                                                      
                                
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# This module implements the transformator. It transforms the syntax tree
# to ease the work of the code generators. Does some transformations:
#
# * inlines iterators
# * inlines constants
# * performs constant folding
# * converts "continue" to "break"; disambiguates "break"
# * introduces method dispatchers
# * performs lambda lifting for closure support
# * transforms 'defer' into a 'try finally' statement

import
  options, ast, astalgo, trees, msgs,
  idents, renderer, types, semfold, magicsys, cgmeth,
  lowerings, liftlocals,
  modulegraphs, lineinfos

proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode

import closureiters, lambdalifting

type
  PTransCon = ref TTransCon
  TTransCon{.final.} = object # part of TContext; stackable
    mapping: TIdNodeTable     # mapping from symbols to nodes
    owner: PSym               # current owner
    forStmt: PNode            # current for stmt
    forLoopBody: PNode   # transformed for loop body
    yieldStmts: int           # we count the number of yield statements,
                              # because we need to introduce new variables
                              # if we encounter the 2nd yield statement
    next: PTransCon           # for stacking

  TTransfContext = object of TPassContext
    module: PSym
    transCon: PTransCon      # top of a TransCon stack
    inlining: int            # > 0 if we are in inlining context (copy vars)
    nestedProcs: int         # > 0 if we are in a nested proc
    contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
    deferDetected, tooEarly: bool
    graph: ModuleGraph
  PTransf = ref TTransfContext

proc newTransNode(a: PNode): PNode {.inline.} =
  result = shallowCopy(a)

proc newTransNode(kind: TNodeKind, info: TLineInfo,
                  sons: int): PNode {.inline.} =
  var x = newNodeI(kind, info)
  newSeq(x.sons, sons)
  result = x

proc newTransNode(kind: TNodeKind, n: PNode,
                  sons: int): PNode {.inline.} =
  var x = newNodeIT(kind, n.info, n.typ)
  newSeq(x.sons, sons)
  x.typ = n.typ
#  x.flags = n.flags
  result = x

proc newTransCon(owner: PSym): PTransCon =
  assert owner != nil
  new(result)
  initIdNodeTable(result.mapping)
  result.owner = owner

proc pushTransCon(c: PTransf, t: PTransCon) =
  t.next = c.transCon
  c.transCon = t

proc popTransCon(c: PTransf) =
  if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
  c.transCon = c.transCon.next

proc getCurrOwner(c: PTransf): PSym =
  if c.transCon != nil: result = c.transCon.owner
  else: result = c.module

proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
  let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), getCurrOwner(c), info)
  r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
  incl(r.flags, sfFromGeneric)
  let owner = getCurrOwner(c)
  if owner.isIterator and not c.tooEarly:
    result = freshVarForClosureIter(c.graph, r, owner)
  else:
    result = newSymNode(r)

proc transform(c: PTransf, n: PNode): PNode

proc transformSons(c: PTransf, n: PNode): PNode =
  result = newTransNode(n)
  for i in 0..<n.len:
    result[i] = transform(c, n[i])

proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode): PNode =
  result = newTransNode(kind, ri.info, 2)
  result[0] = le
  result[1] = ri

proc transformSymAux(c: PTransf, n: PNode): PNode =
  let s = n.sym
  if s.typ != nil and s.typ.callConv == ccClosure:
    if s.kind in routineKinds:
      discard transformBody(c.graph, s, true)
    if s.kind == skIterator:
      if c.tooEarly: return n
      else: return liftIterSym(c.graph, n, getCurrOwner(c))
    elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
      # top level .closure procs are still somewhat supported for 'Nake':
      return makeClosure(c.graph, s, nil, n.info)
  #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
  #  echo n.info, " come heer for ", c.tooEarly
  #  if not c.tooEarly:
  var b: PNode
  var tc = c.transCon
  if sfBorrow in s.flags and s.kind in routineKinds:
    # simply exchange the symbol:
    b = s.getBody
    if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
    b = newSymNode(b.sym, n.info)
  elif c.inlining > 0:
    # see bug #13596: we use ref-based equality in the DFA for destruction
    # injections so we need to ensure unique nodes after iterator inlining
    # which can lead to duplicated for loop bodies! Consider:
    #[
      while remaining > 0:
        if ending == nil:
          yield ms
          break
        ...
        yield ms
    ]#
    b = newSymNode(n.sym, n.info)
  else:
    b = n
  while tc != nil:
    result = idNodeTableGet(tc.mapping, b.sym)
    if result != nil:
      # this slightly convoluted way ensures the line info stays correct:
      if result.kind == nkSym:
        result = copyNode(result)
        result.info = n.info
      return
    tc = tc.next
  result = b

proc transformSym(c: PTransf, n: PNode): PNode =
  result = transformSymAux(c, n)

proc freshVar(c: PTransf; v: PSym): PNode =
  let owner = getCurrOwner(c)
  if owner.isIterator and not c.tooEarly:
    result = freshVarForClosureIter(c.graph, v, owner)
  else:
    var newVar = copySym(v)
    incl(newVar.flags, sfFromGeneric)
    newVar.owner = owner
    result = newSymNode(newVar)

proc transformVarSection(c: PTransf, v: PNode): PNode =
  result = newTransNode(v)
  for i in 0..<v.len:
    var it = v[i]
    if it.kind == nkCommentStmt:
      result[i] = it
    elif it.kind == nkIdentDefs:
      if it[0].kind == nkSym:
        internalAssert(c.graph.config, it.len == 3)
        let x = freshVar(c, it[0].sym)
        idNodeTablePut(c.transCon.mapping, it[0].sym, x)
        var defs = newTransNode(nkIdentDefs, it.info, 3)
        if importantComments(c.graph.config):
          # keep documentation information:
          defs.comment = it.comment
        defs[0] = x
        defs[1] = it[1]
        defs[2] = transform(c, it[2])
        if x.kind == nkSym: x.sym.ast = defs[2]
        result[i] = defs
      else:
        # has been transformed into 'param.x' for closure iterators, so just
        # transform it:
        result[i] = transform(c, it)
    else:
      if it.kind != nkVarTuple:
        internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
      var defs = newTransNode(it.kind, it.info, it.len)
      for j in 0..<it.len-2:
        if it[j].kind == nkSym:
          let x = freshVar(c, it[j].sym)
          idNodeTablePut(c.transCon.mapping, it[j].sym, x)
          defs[j] = x
        else:
          defs[j] = transform(c, it[j])
      assert(it[^2].kind == nkEmpty)
      defs[^2] = newNodeI(nkEmpty, it.info)
      defs[^1] = transform(c, it[^1])
      result[i] = defs

proc transformConstSection(c: PTransf, v: PNode): PNode =
  result = v
  when false:
    result = newTransNode(v)
    for i in 0..<v.len:
      var it = v[i]
      if it.kind == nkCommentStmt:
        result[i] = it
      else:
        if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
        if it[0].kind != nkSym:
          debug it[0]
          internalError(c.graph.config, it.info, "transformConstSection")

        result[i] = it

proc hasContinue(n: PNode): bool =
  case n.kind
  of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
  of nkContinueStmt: result = true
  else:
    for i in 0..<n.len:
      if hasContinue(n[i]): return true

proc newLabel(c: PTransf, n: PNode): PSym =
  result = newSym(skLabel, nil, getCurrOwner(c), n.info)
  result.name = getIdent(c.graph.cache, genPrefix)

proc transformBlock(c: PTransf, n: PNode): PNode =
  var labl: PSym
  if c.inlining > 0:
    labl = newLabel(c, n[0])
    idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
  else:
    labl =
      if n[0].kind != nkEmpty:
        n[0].sym  # already named block? -> Push symbol on the stack
      else:
        newLabel(c, n)
  c.breakSyms.add(labl)
  result = transformSons(c, n)
  discard c.breakSyms.pop
  result[0] = newSymNode(labl)

proc transformLoopBody(c: PTransf, n: PNode): PNode =
  # What if it contains "continue" and "break"? "break" needs
  # an explicit label too, but not the same!

  # We fix this here by making every 'break' belong to its enclosing loop
  # and changing all breaks that belong to a 'block' by annotating it with
  # a label (if it hasn't one already).
  if hasContinue(n):
    let labl = newLabel(c, n)
    c.contSyms.add(labl)

    result = newTransNode(nkBlockStmt, n.info, 2)
    result[0] = newSymNode(labl)
    result[1] = transform(c, n)
    discard c.contSyms.pop()
  else:
    result = transform(c, n)

proc transformWhile(c: PTransf; n: PNode): PNode =
  if c.inlining > 0:
    result = transformSons(c, n)
  else:
    let labl = newLabel(c, n)
    c.breakSyms.add(labl)
    result = newTransNode(nkBlockStmt, n.info, 2)
    result[0] = newSymNode(labl)

    var body = newTransNode(n)
    for i in 0..<n.len-1:
      body[i] = transform(c, n[i])
    body[^1] = transformLoopBody(c, n[^1])
    result[1] = body
    discard c.breakSyms.pop

proc transformBreak(c: PTransf, n: PNode): PNode =
  result = transformSons(c, n)
  if n[0].kind == nkEmpty and c.breakSyms.len > 0:
    let labl = c.breakSyms[c.breakSyms.high]
    result[0] = newSymNode(labl)

proc introduceNewLocalVars(c: PTransf, n: PNode): PNode =
  case n.kind
  of nkSym:
    result = transformSym(c, n)
  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
    # nothing to be done for leaves:
    result = n
  of nkVarSection, nkLetSection:
    result = transformVarSection(c, n)
  of nkClosure:
    # it can happen that for-loop-inlining produced a fresh
    # set of variables, including some computed environment
    # (bug #2604). We need to patch this environment here too:
    let a = n[1]
    if a.kind == nkSym:
      n[1] = transformSymAux(c, a)
    return n
  else:
    result = newTransNode(n)
    for i in 0..<n.len:
      result[i] = introduceNewLocalVars(c, n[i])

proc transformAsgn(c: PTransf, n: PNode): PNode =
  let rhs = n[1]

  if rhs.kind != nkTupleConstr:
    return transformSons(c, n)

  # Unpack the tuple assignment into N temporary variables and then pack them
  # into a tuple: this allows us to get the correct results even when the rhs
  # depends on the value of the lhs
  let letSection = newTransNode(nkLetSection, n.info, rhs.len)
  let newTupleConstr = newTransNode(nkTupleConstr, n.info, rhs.len)
  for i, field in rhs:
    let val = if field.kind == nkExprColonExpr: field[1] else: field
    let def = newTransNode(nkIdentDefs, field.info, 3)
    def[0] = newTemp(c, val.typ, field.info)
    def[1] = newNodeI(nkEmpty, field.info)
    def[2] = transform(c, val)
    letSection[i] = def
    # NOTE: We assume the constructor fields are in the correct order for the
    # given tuple type
    newTupleConstr[i] = def[0]

  newTupleConstr.typ = rhs.typ

  let asgnNode = newTransNode(nkAsgn, n.info, 2)
  asgnNode[0] = transform(c, n[0])
  asgnNode[1] = newTupleConstr

  result = newTransNode(nkStmtList, n.info, 2)
  result[0] = letSection
  result[1] = asgnNode

proc transformYield(c: PTransf, n: PNode): PNode =
  proc asgnTo(lhs: PNode, rhs: PNode): PNode =
    # Choose the right assignment instruction according to the given ``lhs``
    # node since it may not be a nkSym (a stack-allocated skForVar) but a
    # nkDotExpr (a heap-allocated slot into the envP block)
    case lhs.kind
    of nkSym:
      internalAssert c.graph.config, lhs.sym.kind == skForVar
      result = newAsgnStmt(c, nkFastAsgn, lhs, rhs)
    of nkDotExpr:
      result = newAsgnStmt(c, nkAsgn, lhs, rhs)
    else:
      internalAssert c.graph.config, false
  result = newTransNode(nkStmtList, n.info, 0)
  var e = n[0]
  # c.transCon.forStmt.len == 3 means that there is one for loop variable
  # and thus no tuple unpacking:
  if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
  if c.transCon.forStmt.len != 3:
    e = skipConv(e)
    if e.kind in {nkPar, nkTupleConstr}:
      for i in 0..<e.len:
        var v = e[i]
        if v.kind == nkExprColonExpr: v = v[1]
        if c.transCon.forStmt[i].kind == nkVarTuple:
          for j in 0..<c.transCon.forStmt[i].len-1:
            let lhs = c.transCon.forStmt[i][j]
            let rhs = transform(c, newTupleAccess(c.graph, v, j))
            result.add(asgnTo(lhs, rhs))
        else:
          let lhs = c.transCon.forStmt[i]
          let rhs = transform(c, v)
          result.add(asgnTo(lhs, rhs))
    else:
      # Unpack the tuple into the loop variables
      # XXX: BUG: what if `n` is an expression with side-effects?
      for i in 0..<c.transCon.forStmt.len - 2:
        let lhs = c.transCon.forStmt[i]
        let rhs = transform(c, newTupleAccess(c.graph, e, i))
        result.add(asgnTo(lhs, rhs))
  else:
    if c.transCon.forStmt[0].kind == nkVarTuple:
      for i in 0..<c.transCon.forStmt[0].len-1:
        let lhs = c.transCon.forStmt[0][i]
        let rhs = transform(c, newTupleAccess(c.graph, e, i))
        result.add(asgnTo(lhs, rhs))
    else:
      let lhs = c.transCon.forStmt[0]
      let rhs = transform(c, e)
      result.add(asgnTo(lhs, rhs))

  inc(c.transCon.yieldStmts)
  if c.transCon.yieldStmts <= 1:
    # common case
    result.add(c.transCon.forLoopBody)
  else:
    # we need to introduce new local variables:
    result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
  if result.len > 0:
    var changeNode = result[0]
    changeNode.info = c.transCon.forStmt.info
    for i, child in changeNode:
      child.info = changeNode.info

proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode =
  result = transformSons(c, n)
  if c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags: return
  var n = result
  case n[0].kind
  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
    var m = n[0][0]
    if m.kind == a or m.kind == b:
      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
      n[0][0] = m[0]
      result = n[0]
      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
        result.typ = n.typ
      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind)
  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
    var m = n[0][1]
    if m.kind == a or m.kind == b:
      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
      n[0][1] = m[0]
      result = n[0]
      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
        result.typ = n.typ
      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind)
  else:
    if n[0].kind == a or n[0].kind == b:
      # addr ( deref ( x )) --> x
      result = n[0][0]
      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
        result.typ = n.typ

proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
  ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
  ## a closure.

  # we cannot generate a proper thunk here for GC-safety reasons
  # (see internal documentation):
  if c.graph.config.backend == backendJs: return prc
  result = newNodeIT(nkClosure, prc.info, dest)
  var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
  conv.add(newNodeI(nkEmpty, prc.info))
  conv.add(prc)
  if prc.kind == nkClosure:
    internalError(c.graph.config, prc.info, "closure to closure created")
  result.add(conv)
  result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))

proc transformConv(c: PTransf, n: PNode): PNode =
  # numeric types need range checks:
  var dest = skipTypes(n.typ, abstractVarRange)
  var source = skipTypes(n[1].typ, abstractVarRange)
  case dest.kind
  of tyInt..tyInt64, tyEnum, tyChar, tyUInt8..tyUInt32:
    # we don't include uint and uint64 here as these are no ordinal types ;-)
    if not isOrdinalType(source):
      # float -> int conversions. ugh.
      result = transformSons(c, n)
    elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n[1].typ) and
        lastOrd(c.graph.config, n[1].typ) <= lastOrd(c.graph.config, n.typ):
      # BUGFIX: simply leave n as it is; we need a nkConv node,
      # but no range check:
      result = transformSons(c, n)
    else:
      # generate a range check:
      if dest.kind == tyInt64 or source.kind == tyInt64:
        result = newTransNode(nkChckRange64, n, 3)
      else:
        result = newTransNode(nkChckRange, n, 3)
      dest = skipTypes(n.typ, abstractVar)
      result[0] = transform(c, n[1])
      result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest)
      result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest)
  of tyFloat..tyFloat128:
    # XXX int64 -> float conversion?
    if skipTypes(n.typ, abstractVar).kind == tyRange:
      result = newTransNode(nkChckRangeF, n, 3)
      dest = skipTypes(n.typ, abstractVar)
      result[0] = transform(c, n[1])
      result[1] = copyTree(dest.n[0])
      result[2] = copyTree(dest.n[1])
    else:
      result = transformSons(c, n)
  of tyOpenArray, tyVarargs:
    result = transform(c, n[1])
    #result = transformSons(c, n)
    result.typ = takeType(n.typ, n[1].typ)
    #echo n.info, " came here and produced ", typeToString(result.typ),
    #   " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
  of tyCString:
    if source.kind == tyString:
      result = newTransNode(nkStringToCString, n, 1)
      result[0] = transform(c, n[1])
    else:
      result = transformSons(c, n)
  of tyString:
    if source.kind == tyCString:
      result = newTransNode(nkCStringToString, n, 1)
      result[0] = transform(c, n[1])
    else:
      result = transformSons(c, n)
  of tyRef, tyPtr:
    dest = skipTypes(dest, abstractPtrs)
    source = skipTypes(source, abstractPtrs)
    if source.kind == tyObject:
      var diff = inheritanceDiff(dest, source)
      if diff < 0:
        result = newTransNode(nkObjUpConv, n, 1)
        result[0] = transform(c, n[1])
      elif diff > 0 and diff != high(int):
        result = newTransNode(nkObjDownConv, n, 1)
        result[0] = transform(c, n[1])
      else:
        result = transform(c, n[1])
    else:
      result = transformSons(c, n)
  of tyObject:
    var diff = inheritanceDiff(dest, source)
    if diff < 0:
      result = newTransNode(nkObjUpConv, n, 1)
      result[0] = transform(c, n[1])
    elif diff > 0 and diff != high(int):
      result = newTransNode(nkObjDownConv, n, 1)
      result[0] = transform(c, n[1])
    else:
      result = transform(c, n[1])
  of tyGenericParam, tyOrdinal:
    result = transform(c, n[1])
    # happens sometimes for generated assignments, etc.
  of tyProc:
    result = transformSons(c, n)
    if dest.callConv == ccClosure and source.callConv == ccNimCall:
      result = generateThunk(c, result[1], dest)
  else:
    result = transformSons(c, n)

type
  TPutArgInto = enum
    paDirectMapping, paFastAsgn, paFastAsgnTakeTypeFromArg
    paVarAsgn, paComplexOpenarray

proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
  # This analyses how to treat the mapping "formal <-> arg" in an
  # inline context.
  if formal.kind == tyTypeDesc: return paDirectMapping
  if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
    case arg.kind
    of nkStmtListExpr:
      return paComplexOpenarray
    of nkBracket:
      return paFastAsgnTakeTypeFromArg
    else:
      # XXX incorrect, causes #13417 when `arg` has side effects.
      return paDirectMapping
  case arg.kind
  of nkEmpty..nkNilLit:
    result = paDirectMapping
  of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr:
    result = putArgInto(arg[0], formal)
  of nkCurly, nkBracket:
    for i in 0..<arg.len:
      if putArgInto(arg[i], formal) != paDirectMapping:
        return paFastAsgn
    result = paDirectMapping
  of nkPar, nkTupleConstr, nkObjConstr:
    for i in 0..<arg.len:
      let a = if arg[i].kind == nkExprColonExpr: arg[i][1]
              else: arg[0]
      if putArgInto(a, formal) != paDirectMapping:
        return paFastAsgn
    result = paDirectMapping
  else:
    if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
    else: result = paFastAsgn

proc findWrongOwners(c: PTransf, n: PNode) =
  if n.kind == nkVarSection:
    let x = n[0][0]
    if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
      internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
        x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
  else:
    for i in 0..<n.safeLen: findWrongOwners(c, n[i])

proc isSimpleIteratorVar(iter: PSym): bool =
  proc rec(n: PNode; owner: PSym; dangerousYields: var int) =
    case n.kind
    of nkEmpty..nkNilLit: discard
    of nkYieldStmt:
      if n[0].kind == nkSym and n[0].sym.owner == owner:
        discard "good: yield a single variable that we own"
      else:
        inc dangerousYields
    else:
      for c in n: rec(c, owner, dangerousYields)

  var dangerousYields = 0
  rec(iter.ast[bodyPos], iter, dangerousYields)
  result = dangerousYields == 0

proc transformFor(c: PTransf, n: PNode): PNode =
  # generate access statements for the parameters (unless they are constant)
  # put mapping from formal parameters to actual parameters
  if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")

  var call = n[^2]

  let labl = newLabel(c, n)
  result = newTransNode(nkBlockStmt, n.info, 2)
  result[0] = newSymNode(labl)
  if call.typ.isNil:
    # see bug #3051
    result[1] = newNode(nkEmpty)
    return result
  c.breakSyms.add(labl)
  if call.kind notin nkCallKinds or call[0].kind != nkSym or
      call[0].typ.skipTypes(abstractInst).callConv == ccClosure:
    result[1] = n
    result[1][^1] = transformLoopBody(c, n[^1])
    result[1][^2] = transform(c, n[^2])
    result[1] = lambdalifting.liftForLoop(c.graph, result[1], getCurrOwner(c))
    discard c.breakSyms.pop
    return result

  #echo "transforming: ", renderTree(n)
  var stmtList = newTransNode(nkStmtList, n.info, 0)
  result[1] = stmtList

  var loopBody = transformLoopBody(c, n[^1])

  discard c.breakSyms.pop

  let iter = call[0].sym

  var v = newNodeI(nkVarSection, n.info)
  for i in 0..<n.len - 2:
    if n[i].kind == nkVarTuple:
      for j in 0..<n[i].len-1:
        addVar(v, copyTree(n[i][j])) # declare new vars
    else:
      if n[i].kind == nkSym and isSimpleIteratorVar(iter):
        incl n[i].sym.flags, sfCursor
      addVar(v, copyTree(n[i])) # declare new vars
  stmtList.add(v)


  # Bugfix: inlined locals belong to the invoking routine, not to the invoked
  # iterator!
  var newC = newTransCon(getCurrOwner(c))
  newC.forStmt = n
  newC.forLoopBody = loopBody
  # this can fail for 'nimsuggest' and 'check':
  if iter.kind != skIterator: return result
  # generate access statements for the parameters (unless they are constant)
  pushTransCon(c, newC)
  for i in 1..<call.len:
    var arg = transform(c, call[i])
    let ff = skipTypes(iter.typ, abstractInst)
    # can happen for 'nim check':
    if i >= ff.n.len: return result
    var formal = ff.n[i].sym
    let pa = putArgInto(arg, formal.typ)
    case pa
    of paDirectMapping:
      idNodeTablePut(newC.mapping, formal, arg)
    of paFastAsgn, paFastAsgnTakeTypeFromArg:
      var t = formal.typ
      if pa == paFastAsgnTakeTypeFromArg:
        t = arg.typ
      elif formal.ast != nil and formal.ast.typ.destructor != nil and t.destructor == nil:
        t = formal.ast.typ # better use the type that actually has a destructor.
      elif t.destructor == nil and arg.typ.destructor != nil:
        t = arg.typ
      # generate a temporary and produce an assignment statement:
      var temp = newTemp(c, t, formal.info)
      addVar(v, temp)
      stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg))
      idNodeTablePut(newC.mapping, formal, temp)
    of paVarAsgn:
      assert(skipTypes(formal.typ, abstractInst).kind in {tyVar})
      idNodeTablePut(newC.mapping, formal, arg)
      # XXX BUG still not correct if the arg has a side effect!
    of paComplexOpenarray:
      # arrays will deep copy here (pretty bad).
      var temp = newTemp(c, arg.typ, formal.info)
      addVar(v, temp)
      stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg))
      idNodeTablePut(newC.mapping, formal, temp)

  let body = transformBody(c.graph, iter, true)
  pushInfoContext(c.graph.config, n.info)
  inc(c.inlining)
  stmtList.add(transform(c, body))
  #findWrongOwners(c, stmtList.pnode)
  dec(c.inlining)
  popInfoContext(c.graph.config)
  popTransCon(c)
  # echo "transformed: ", stmtList.renderTree

proc transformCase(c: PTransf, n: PNode): PNode =
  # removes `elif` branches of a case stmt
  # adds ``else: nil`` if needed for the code generator
  result = newTransNode(nkCaseStmt, n, 0)
  var ifs: PNode = nil
  for it in n:
    var e = transform(c, it)
    case it.kind
    of nkElifBranch:
      if ifs == nil:
        # Generate the right node depending on whether `n` is used as a stmt or
        # as an expr
        let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
        ifs = newTransNode(kind, it.info, 0)
        ifs.typ = n.typ
      ifs.add(e)
    of nkElse:
      if ifs == nil: result.add(e)
      else: ifs.add(e)
    else:
      result.add(e)
  if ifs != nil:
    var elseBranch = newTransNode(nkElse, n.info, 1)
    elseBranch[0] = ifs
    result.add(elseBranch)
  elif result.lastSon.kind != nkElse and not (
      skipTypes(n[0].typ, abstractVarRange).kind in
        {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64}):
    # fix a stupid code gen bug by normalizing:
    var elseBranch = newTransNode(nkElse, n.info, 1)
    elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
    result.add(elseBranch)

proc transformArrayAccess(c: PTransf, n: PNode): PNode =
  # XXX this is really bad; transf should use a proper AST visitor
  if n[0].kind == nkSym and n[0].sym.kind == skType:
    result = n
  else:
    result = newTransNode(n)
    for i in 0..<n.len:
      result[i] = transform(c, skipConv(n[i]))

proc getMergeOp(n: PNode): PSym =
  case n.kind
  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
     nkCallStrLit:
    if n[0].kind == nkSym and n[0].sym.magic == mConStrStr:
      result = n[0].sym
  else: discard

proc flattenTreeAux(d, a: PNode, op: PSym) =
  let op2 = getMergeOp(a)
  if op2 != nil and
      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
    for i in 1..<a.len: flattenTreeAux(d, a[i], op)
  else:
    d.add copyTree(a)

proc flattenTree(root: PNode): PNode =
  let op = getMergeOp(root)
  if op != nil:
    result = copyNode(root)
    result.add copyTree(root[0])
    flattenTreeAux(result, root, op)
  else:
    result = root

proc transformCall(c: PTransf, n: PNode): PNode =
  var n = flattenTree(n)
  let op = getMergeOp(n)
  let magic = getMagic(n)
  if op != nil and op.magic != mNone and n.len >= 3:
    result = newTransNode(nkCall, n, 0)
    result.add(transform(c, n[0]))
    var j = 1
    while j < n.len:
      var a = transform(c, n[j])
      inc(j)
      if isConstExpr(a):
        while (j < n.len):
          let b = transform(c, n[j])
          if not isConstExpr(b): break
          a = evalOp(op.magic, n, a, b, nil, c.graph)
          inc(j)
      result.add(a)
    if result.len == 2: result = result[1]
  elif magic == mAddr:
    result = newTransNode(nkAddr, n, 1)
    result[0] = n[1]
    result = transformAddrDeref(c, result, nkDerefExpr, nkHiddenDeref)
  elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
    # for bindSym(myconst) we MUST NOT perform constant folding:
    result = n
  elif magic == mProcCall:
    # but do not change to its dispatcher:
    result = transformSons(c, n[1])
  elif magic == mStrToStr:
    result = transform(c, n[1])
  else:
    let s = transformSons(c, n)
    # bugfix: check after 'transformSons' if it's still a method call:
    # use the dispatcher for the call:
    if s[0].kind == nkSym and s[0].sym.kind == skMethod:
      when false:
        let t = lastSon(s[0].sym.ast)
        if t.kind != nkSym or sfDispatcher notin t.sym.flags:
          methodDef(s[0].sym, false)
      result = methodCall(s, c.graph.config)
    else:
      result = s

proc transformExceptBranch(c: PTransf, n: PNode): PNode =
  if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
    let excTypeNode = n[0][1]
    let actions = newTransNode(nkStmtListExpr, n[1], 2)
    # Generating `let exc = (excType)(getCurrentException())`
    # -> getCurrentException()
    let excCall = callCodegenProc(c.graph, "getCurrentException")
    # -> (excType)
    let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
    convNode[0] = newNodeI(nkEmpty, n.info)
    convNode[1] = excCall
    convNode.typ = excTypeNode.typ.toRef()
    # -> let exc = ...
    let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
    identDefs[0] = n[0][2]
    identDefs[1] = newNodeI(nkEmpty, n.info)
    identDefs[2] = convNode

    let letSection = newTransNode(nkLetSection, n[1].info, 1)
    letSection[0] = identDefs
    # Place the let statement and body of the 'except' branch into new stmtList.
    actions[0] = letSection
    actions[1] = transform(c, n[1])
    # Overwrite 'except' branch body with our stmtList.
    result = newTransNode(nkExceptBranch, n[1].info, 2)
    # Replace the `Exception as foobar` with just `Exception`.
    result[0] = transform(c, n[0][1])
    result[1] = actions
  else:
    result = transformSons(c, n)

proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
  result = n
  for i in 0..<n.safeLen:
    result[i] = commonOptimizations(g, c, n[i])
  var op = getMergeOp(n)
  if (op != nil) and (op.magic != mNone) and (n.len >= 3):
    result = newNodeIT(nkCall, n.info, n.typ)
    result.add(n[0])
    var args = newNode(nkArgList)
    flattenTreeAux(args, n, op)
    var j = 0
    while j < args.len:
      var a = args[j]
      inc(j)
      if isConstExpr(a):
        while j < args.len:
          let b = args[j]
          if not isConstExpr(b): break
          a = evalOp(op.magic, result, a, b, nil, g)
          inc(j)
      result.add(a)
    if result.len == 2: result = result[1]
  else:
    var cnst = getConstExpr(c, n, g)
    # we inline constants if they are not complex constants:
    if cnst != nil and not dontInlineConstant(n, cnst):
      result = cnst
    else:
      result = n

proc transform(c: PTransf, n: PNode): PNode =
  when false:
    var oldDeferAnchor: PNode
    if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
                  nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally,
                  nkBlockStmt, nkBlockExpr}:
      oldDeferAnchor = c.deferAnchor
      c.deferAnchor = n
  case n.kind
  of nkSym:
    result = transformSym(c, n)
  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
    # nothing to be done for leaves:
    result = n
  of nkBracketExpr: result = transformArrayAccess(c, n)
  of procDefs:
    var s = n[namePos].sym
    if n.typ != nil and s.typ.callConv == ccClosure:
      result = transformSym(c, n[namePos])
      # use the same node as before if still a symbol:
      if result.kind == nkSym: result = n
    else:
      result = n
  of nkMacroDef:
    # XXX no proper closure support yet:
    when false:
      if n[genericParamsPos].kind == nkEmpty:
        var s = n[namePos].sym
        n[bodyPos] = transform(c, s.getBody)
        if n.kind == nkMethodDef: methodDef(s, false)
    result = n
  of nkForStmt:
    result = transformFor(c, n)
  of nkParForStmt:
    result = transformSons(c, n)
  of nkCaseStmt:
    result = transformCase(c, n)
  of nkWhileStmt: result = transformWhile(c, n)
  of nkBlockStmt, nkBlockExpr:
    result = transformBlock(c, n)
  of nkDefer:
    c.deferDetected = true
    result = transformSons(c, n)
    when false:
      let deferPart = newNodeI(nkFinally, n.info)
      deferPart.add n[0]
      let tryStmt = newNodeI(nkTryStmt, n.info)
      if c.deferAnchor.isNil:
        tryStmt.add c.root
        c.root = tryStmt
        result = tryStmt
      else:
        # modify the corresponding *action*, don't rely on nkStmtList:
        tryStmt.add c.deferAnchor[^1]
        c.deferAnchor[^1] = tryStmt
        result = newTransNode(nkCommentStmt, n.info, 0)
      tryStmt.add deferPart
      # disable the original 'defer' statement:
      n.kind = nkEmpty
  of nkContinueStmt:
    result = newNodeI(nkBreakStmt, n.info)
    var labl = c.contSyms[c.contSyms.high]
    result.add(newSymNode(labl))
  of nkBreakStmt: result = transformBreak(c, n)
  of nkCallKinds:
    result = transformCall(c, n)
  of nkAddr, nkHiddenAddr:
    result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
  of nkDerefExpr, nkHiddenDeref:
    result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
    result = transformConv(c, n)
  of nkDiscardStmt:
    result = n
    if n[0].kind != nkEmpty:
      result = transformSons(c, n)
      if isConstExpr(result[0]):
        # ensure that e.g. discard "some comment" gets optimized away
        # completely:
        result = newNode(nkCommentStmt)
  of nkCommentStmt, nkTemplateDef, nkImportStmt, nkStaticStmt,
      nkExportStmt, nkExportExceptStmt:
    return n
  of nkConstSection:
    # do not replace ``const c = 3`` with ``const 3 = 3``
    return transformConstSection(c, n)
  of nkTypeSection, nkTypeOfExpr:
    # no need to transform type sections:
    return n
  of nkVarSection, nkLetSection:
    if c.inlining > 0:
      # we need to copy the variables for multiple yield statements:
      result = transformVarSection(c, n)
    else:
      result = transformSons(c, n)
  of nkYieldStmt:
    if c.inlining > 0:
      result = transformYield(c, n)
    else:
      result = transformSons(c, n)
  of nkAsgn:
    result = transformAsgn(c, n)
  of nkIdentDefs, nkConstDef:
    result = n
    result[0] = transform(c, n[0])
    # Skip the second son since it only contains an unsemanticized copy of the
    # variable type used by docgen
    result[2] = transform(c, n[2])
    # XXX comment handling really sucks:
    if importantComments(c.graph.config):
      result.comment = n.comment
  of nkClosure:
    # it can happen that for-loop-inlining produced a fresh
    # set of variables, including some computed environment
    # (bug #2604). We need to patch this environment here too:
    let a = n[1]
    if a.kind == nkSym:
      n[1] = transformSymAux(c, a)
    return n
  of nkExceptBranch:
    result = transformExceptBranch(c, n)
  else:
    result = transformSons(c, n)
  when false:
    if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor

  # Constants can be inlined here, but only if they cannot result in a cast
  # in the back-end (e.g. var p: pointer = someProc)
  let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
                          n.typ != nil and
                          n.typ.kind == tyPointer
  if not exprIsPointerCast:
    var cnst = getConstExpr(c.module, result, c.graph)
    # we inline constants if they are not complex constants:
    if cnst != nil and not dontInlineConstant(n, cnst):
      result = cnst # do not miss an optimization

proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
  # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
  # this step! We have to rely that the semantic pass transforms too errornous
  # nodes into an empty node.
  if nfTransf in n.flags: return n
  pushTransCon(c, newTransCon(owner))
  result = transform(c, n)
  popTransCon(c)
  incl(result.flags, nfTransf)

proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
  new(result)
  result.contSyms = @[]
  result.breakSyms = @[]
  result.module = module
  result.graph = g

proc flattenStmts(n: PNode) =
  var goOn = true
  while goOn:
    goOn = false
    var i = 0
    while i < n.len:
      let it = n[i]
      if it.kind in {nkStmtList, nkStmtListExpr}:
        n.sons[i..i] = it.sons[0..<it.len]
        goOn = true
      inc i

proc liftDeferAux(n: PNode) =
  if n.kind in {nkStmtList, nkStmtListExpr}:
    flattenStmts(n)
    var goOn = true
    while goOn:
      goOn = false
      let last = n.len-1
      for i in 0..last:
        if n[i].kind == nkDefer:
          let deferPart = newNodeI(nkFinally, n[i].info)
          deferPart.add n[i][0]
          var tryStmt = newNodeIT(nkTryStmt, n[i].info, n.typ)
          var body = newNodeIT(n.kind, n[i].info, n.typ)
          if i < last:
            body.sons = n.sons[(i+1)..last]
          tryStmt.add body
          tryStmt.add deferPart
          n[i] = tryStmt
          n.sons.setLen(i+1)
          n.typ = tryStmt.typ
          goOn = true
          break
  for i in 0..n.safeLen-1:
    liftDeferAux(n[i])

template liftDefer(c, root) =
  if c.deferDetected:
    liftDeferAux(root)

proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode =
  assert prc.kind in routineKinds

  if prc.transformedBody != nil:
    result = prc.transformedBody
  elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
    result = prc.ast[bodyPos]
  else:
    prc.transformedBody = newNode(nkEmpty) # protects from recursion
    var c = openTransf(g, prc.getModule, "")
    result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
    result = processTransf(c, result, prc)
    liftDefer(c, result)
    result = liftLocalsIfRequested(prc, result, g.cache, g.config)

    if prc.isIterator:
      result = g.transformClosureIterator(prc, result)

    incl(result.flags, nfTransf)

    if cache or prc.typ.callConv == ccInline:
      # genProc for inline procs will be called multiple times from different modules,
      # it is important to transform exactly once to get sym ids and locations right
      prc.transformedBody = result
    else:
      prc.transformedBody = nil

  #if prc.name.s == "main":
  #  echo "transformed into ", renderTree(result, {renderIds})

proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  if nfTransf in n.flags:
    result = n
  else:
    var c = openTransf(g, module, "")
    result = processTransf(c, n, module)
    liftDefer(c, result)
    #result = liftLambdasForTopLevel(module, result)
    incl(result.flags, nfTransf)

proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
  if nfTransf in n.flags:
    result = n
  else:
    var c = openTransf(g, module, "")
    result = processTransf(c, n, module)
    liftDefer(c, result)
    # expressions are not to be injected with destructor calls as that
    # the list of top level statements needs to be collected before.
    incl(result.flags, nfTransf)