summary refs log tree commit diff stats
path: root/rod/transf.nim
diff options
context:
space:
mode:
Diffstat (limited to 'rod/transf.nim')
-rwxr-xr-xrod/transf.nim747
1 files changed, 0 insertions, 747 deletions
diff --git a/rod/transf.nim b/rod/transf.nim
deleted file mode 100755
index 9eddcbe68..000000000
--- a/rod/transf.nim
+++ /dev/null
@@ -1,747 +0,0 @@
-#
-#
-#           The Nimrod Compiler
-#        (c) Copyright 2010 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
-# * performes contant folding
-# * converts "continue" to "break"
-# * introduces method dispatchers
-
-import 
-  strutils, lists, options, ast, astalgo, trees, treetab, evals, msgs, os, 
-  idents, rnimsyn, types, passes, semfold, magicsys, cgmeth
-
-const 
-  genPrefix* = ":tmp"         # prefix for generated names
-
-proc transfPass*(): TPass
-# implementation
-
-type 
-  PTransNode* = distinct PNode
-  
-  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: PTransNode   # 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 passes.TPassContext
-    module: PSym
-    transCon: PTransCon      # top of a TransCon stack
-    inlining: int            # > 0 if we are in inlining context (copy vars)
-    blocksyms: seq[PSym]
-  
-  PTransf = ref TTransfContext
-
-proc newTransNode(a: PNode): PTransNode {.inline.} = 
-  result = PTransNode(shallowCopy(a))
-
-proc newTransNode(kind: TNodeKind, info: TLineInfo, 
-                  sons: int): PTransNode {.inline.} = 
-  var x = newNodeI(kind, info)
-  newSeq(x.sons, sons)
-  result = x.PTransNode
-
-proc newTransNode(kind: TNodeKind, n: PNode, 
-                  sons: int): PTransNode {.inline.} = 
-  var x = newNodeIT(kind, n.info, n.typ)
-  newSeq(x.sons, sons)
-  x.typ = n.typ
-  result = x.PTransNode
-
-proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} = 
-  var n = PNode(a)
-  n.sons[i] = PNode(x)
-
-proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} = 
-  var n = PNode(a)
-  result = n.sons[i].PTransNode
-  
-proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
-proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
-
-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("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): PSym = 
-  result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c))
-  result.info = info
-  result.typ = skipTypes(typ, {tyGenericInst})
-  incl(result.flags, sfFromGeneric)
-
-proc transform(c: PTransf, n: PNode): PTransNode
-
-proc transformSons(c: PTransf, n: PNode): PTransNode =
-  result = newTransNode(n)
-  for i in countup(0, sonsLen(n)-1): 
-    result[i] = transform(c, n.sons[i])
-
-# Transforming iterators into non-inlined versions is pretty hard, but
-# unavoidable for not bloating the code too much. If we had direct access to
-# the program counter, things'd be much easier.
-# ::
-#
-#  iterator items(a: string): char =
-#    var i = 0
-#    while i < length(a):
-#      yield a[i]
-#      inc(i)
-#
-#  for ch in items("hello world"): # `ch` is an iteration variable
-#    echo(ch)
-#
-# Should be transformed into::
-#
-#  type
-#    TItemsClosure = record
-#      i: int
-#      state: int
-#  proc items(a: string, c: var TItemsClosure): char =
-#    case c.state
-#    of 0: goto L0 # very difficult without goto!
-#    of 1: goto L1 # can be implemented by GCC's computed gotos
-#
-#    block L0:
-#      c.i = 0
-#      while c.i < length(a):
-#        c.state = 1
-#        return a[i]
-#        block L1: inc(c.i)
-#
-# More efficient, but not implementable::
-#
-#  type
-#    TItemsClosure = record
-#      i: int
-#      pc: pointer
-#
-#  proc items(a: string, c: var TItemsClosure): char =
-#    goto c.pc
-#    c.i = 0
-#    while c.i < length(a):
-#      c.pc = label1
-#      return a[i]
-#      label1: inc(c.i)
-#
-
-proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = 
-  result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
-  result[0] = PTransNode(le)
-  result[1] = ri
-
-proc transformSymAux(c: PTransf, n: PNode): PNode = 
-  var b: PNode
-  if (n.kind != nkSym): internalError(n.info, "transformSym")
-  var tc = c.transCon
-  if sfBorrow in n.sym.flags: 
-    # simply exchange the symbol:
-    b = n.sym.ast.sons[codePos]
-    if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
-    b = newSymNode(b.sym)
-    b.info = n.info
-  else: 
-    b = n
-  while tc != nil: 
-    result = IdNodeTableGet(tc.mapping, b.sym)
-    if result != nil: return
-    tc = tc.next
-  result = b
-  case b.sym.kind
-  of skConst, skEnumField: 
-    # BUGFIX: skEnumField was missing
-    if not (skipTypes(b.sym.typ, abstractInst).kind in ConstantDataTypes): 
-      result = getConstExpr(c.module, b)
-      if result == nil: InternalError(b.info, "transformSym: const")
-  else: 
-    nil
-
-proc transformSym(c: PTransf, n: PNode): PTransNode = 
-  result = PTransNode(transformSymAux(c, n))
-
-proc transformVarSection(c: PTransf, v: PNode): PTransNode =
-  result = newTransNode(v)
-  for i in countup(0, sonsLen(v)-1): 
-    var it = v.sons[i]
-    if it.kind == nkCommentStmt: 
-      result[i] = PTransNode(it)
-    elif it.kind == nkIdentDefs: 
-      if (it.sons[0].kind != nkSym):
-        InternalError(it.info, "transformVarSection")
-      var newVar = copySym(it.sons[0].sym)
-      incl(newVar.flags, sfFromGeneric) 
-      # fixes a strange bug for rodgen:
-      #include(it.sons[0].sym.flags, sfFromGeneric);
-      newVar.owner = getCurrOwner(c)
-      IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar))
-      var defs = newTransNode(nkIdentDefs, it.info, 3)
-      defs[0] = newSymNode(newVar).PTransNode
-      defs[1] = it.sons[1].PTransNode
-      defs[2] = transform(c, it.sons[2])
-      result[i] = defs
-    else: 
-      if it.kind != nkVarTuple: 
-        InternalError(it.info, "transformVarSection: not nkVarTuple")
-      var L = sonsLen(it)
-      var defs = newTransNode(it.kind, it.info, L)
-      for j in countup(0, L-3): 
-        var newVar = copySym(it.sons[j].sym)
-        incl(newVar.flags, sfFromGeneric)
-        newVar.owner = getCurrOwner(c)
-        IdNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar))
-        defs[j] = newSymNode(newVar).PTransNode
-      assert(it.sons[L-2] == nil)
-      defs[L-1] = transform(c, it.sons[L-1])
-      result[i] = defs
-
-proc hasContinue(n: PNode): bool = 
-  if n == nil: return 
-  case n.kind
-  of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: nil
-  of nkContinueStmt: result = true
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
-      if hasContinue(n.sons[i]): return true
-
-proc transformLoopBody(c: PTransf, n: PNode): PTransNode =  
-  # XXX BUG: What if it contains "continue" and "break"? "break" needs 
-  # an explicit label too, but not the same!
-  if hasContinue(n):
-    var labl = newSym(skLabel, nil, getCurrOwner(c))
-    labl.name = getIdent(genPrefix & $labl.id)
-    labl.info = n.info
-    c.blockSyms.add(labl)
-
-    result = newTransNode(nkBlockStmt, n.info, 2)
-    result[0] = newSymNode(labl).PTransNode
-    result[1] = transform(c, n)
-    discard c.blockSyms.pop()
-  else: 
-    result = transform(c, n)
-
-proc skipConv(n: PNode): PNode = 
-  case n.kind
-  of nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, nkChckRangeF, 
-     nkChckRange64: 
-    result = n.sons[0]
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
-    result = n.sons[1]
-  else: result = n
-  
-proc newTupleAccess(tup: PNode, i: int): PNode = 
-  result = newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i])
-  addSon(result, copyTree(tup))
-  var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
-  lit.intVal = i
-  addSon(result, lit)
-
-proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = 
-  # XXX: BUG: what if `n` is an expression with side-effects?
-  for i in countup(0, sonsLen(c.transCon.forStmt) - 3): 
-    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
-        transform(c, newTupleAccess(n, i))))
-
-proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = 
-  if n == nil: return
-  case n.kind
-  of nkSym: 
-    return transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
-    # nothing to be done for leaves:
-    result = PTransNode(n)
-  of nkVarSection:
-    result = transformVarSection(c, n)
-  else:
-    result = newTransNode(n)
-    for i in countup(0, sonsLen(n)-1): 
-      result[i] =  introduceNewLocalVars(c, n.sons[i])
-
-proc transformYield(c: PTransf, n: PNode): PTransNode = 
-  result = newTransNode(nkStmtList, n.info, 0)
-  var e = n.sons[0]
-  if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple: 
-    e = skipConv(e)
-    if e.kind == nkPar: 
-      for i in countup(0, sonsLen(e) - 1): 
-        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
-                                transform(c, e.sons[i])))
-    else: 
-      unpackTuple(c, e, result)
-  else: 
-    var x = transform(c, e)
-    add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
-  
-  inc(c.transCon.yieldStmts)
-  if c.transCon.yieldStmts <= 1:
-    # common case
-    add(result, c.transCon.forLoopBody)
-  else: 
-    # we need to introduce new local variables:
-    add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.pnode))
-
-proc addVar(father, v: PNode) = 
-  var vpart = newNodeI(nkIdentDefs, v.info)
-  addSon(vpart, v)
-  addSon(vpart, nil)
-  addSon(vpart, nil)
-  addSon(father, vpart)
-
-proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = 
-  case n.sons[0].kind
-  of nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange, nkChckRangeF, 
-     nkChckRange64: 
-    var m = n.sons[0].sons[0]
-    if (m.kind == a) or (m.kind == b): 
-      # addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x)
-      var x = copyTree(n)
-      x.sons[0].sons[0] = m.sons[0]
-      result = transform(c, x.sons[0])
-
-      #result = newTransNode(n.sons[0])
-      #result[0] = transform(c, m.sons[0])
-    else: 
-      result = transformSons(c, n)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
-    var m = n.sons[0].sons[1]
-    if (m.kind == a) or (m.kind == b): 
-      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      
-      var x = copyTree(n)
-      x.sons[0].sons[1] = m.sons[0]
-      result = transform(c, x.sons[0])
-      
-      #result = newTransNode(n.sons[0])
-      #result[1] = transform(c, m.sons[0])
-      
-      #if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
-      #  debug(result.pnode)
-      #  liMessage(n.info, warnUser, 
-      #    "nkPassAsOpenArray introduced here " & renderTree(n))
-    else:
-      result = transformSons(c, n)
-  else: 
-    if (n.sons[0].kind == a) or (n.sons[0].kind == b): 
-      # addr ( deref ( x )) --> x
-      result = transform(c, n.sons[0].sons[0])
-    else:
-      result = transformSons(c, n)
-
-proc transformConv(c: PTransf, n: PNode): PTransNode = 
-  # numeric types need range checks:
-  var dest = skipTypes(n.typ, abstractVarRange)
-  var source = skipTypes(n.sons[1].typ, abstractVarRange)
-  case dest.kind
-  of tyInt..tyInt64, tyEnum, tyChar, tyBool: 
-    if not isOrdinalType(source):
-      # XXX int64 -> float conversion?
-      result = transformSons(c, n)
-    elif firstOrd(dest) <= firstOrd(source) and
-        lastOrd(source) <= lastOrd(dest): 
-      # 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.sons[1])
-      result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
-      result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
-  of tyFloat..tyFloat128: 
-    if skipTypes(n.typ, abstractVar).kind == tyRange: 
-      result = newTransNode(nkChckRangeF, n, 3)
-      dest = skipTypes(n.typ, abstractVar)
-      result[0] = transform(c, n.sons[1])
-      result[1] = copyTree(dest.n.sons[0]).PTransNode
-      result[2] = copyTree(dest.n.sons[1]).PTransNode
-    else:
-      result = transformSons(c, n)
-  of tyOpenArray: 
-    result = newTransNode(nkPassAsOpenArray, n, 1)
-    result[0] = transform(c, n.sons[1])
-  of tyCString: 
-    if source.kind == tyString: 
-      result = newTransNode(nkStringToCString, n, 1)
-      result[0] = transform(c, n.sons[1])
-    else:
-      result = transformSons(c, n)
-  of tyString: 
-    if source.kind == tyCString: 
-      result = newTransNode(nkCStringToString, n, 1)
-      result[0] = transform(c, n.sons[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.sons[1])
-      elif diff > 0: 
-        result = newTransNode(nkObjDownConv, n, 1)
-        result[0] = transform(c, n.sons[1])
-      else: 
-        result = transform(c, n.sons[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.sons[1])
-    elif diff > 0: 
-      result = newTransNode(nkObjDownConv, n, 1)
-      result[0] = transform(c, n.sons[1])
-    else: 
-      result = transform(c, n.sons[1])
-  of tyGenericParam, tyOrdinal: 
-    result = transform(c, n.sons[1])
-    # happens sometimes for generated assignments, etc.
-  else: 
-    result = transformSons(c, n)
-
-proc skipPassAsOpenArray(n: PNode): PNode = 
-  result = n
-  while result.kind == nkPassAsOpenArray: result = result.sons[0]
-  
-type 
-  TPutArgInto = enum 
-    paDirectMapping, paFastAsgn, paVarAsgn
-
-proc putArgInto(arg: PNode, formal: PType): TPutArgInto = 
-  # This analyses how to treat the mapping "formal <-> arg" in an
-  # inline context.
-  if skipTypes(formal, abstractInst).kind == tyOpenArray: 
-    return paDirectMapping    # XXX really correct?
-                              # what if ``arg`` has side-effects?
-  case arg.kind
-  of nkEmpty..nkNilLit: 
-    result = paDirectMapping
-  of nkPar, nkCurly, nkBracket: 
-    result = paFastAsgn
-    for i in countup(0, sonsLen(arg) - 1): 
-      if putArgInto(arg.sons[i], formal) != paDirectMapping: return 
-    result = paDirectMapping
-  else: 
-    if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
-    else: result = paFastAsgn
-  
-proc transformFor(c: PTransf, n: PNode): PTransNode = 
-  # generate access statements for the parameters (unless they are constant)
-  # put mapping from formal parameters to actual parameters
-  if n.kind != nkForStmt: InternalError(n.info, "transformFor")
-  result = newTransNode(nkStmtList, n.info, 0)
-  var length = sonsLen(n)
-  var loopBody = transformLoopBody(c, n.sons[length-1])
-  var v = newNodeI(nkVarSection, n.info)
-  for i in countup(0, length - 3): 
-    addVar(v, copyTree(n.sons[i])) # declare new vars
-  add(result, v.ptransNode)
-  var call = n.sons[length - 2]
-  if (call.kind != nkCall) or (call.sons[0].kind != nkSym): 
-    InternalError(call.info, "transformFor")
-  
-  var newC = newTransCon(call.sons[0].sym)
-  newC.forStmt = n
-  newC.forLoopBody = loopBody
-  if (newC.owner.kind != skIterator): 
-    InternalError(call.info, "transformFor") 
-  # generate access statements for the parameters (unless they are constant)
-  pushTransCon(c, newC)
-  for i in countup(1, sonsLen(call) - 1): 
-    var arg = skipPassAsOpenArray(transform(c, call.sons[i]).pnode)
-    var formal = skipTypes(newC.owner.typ, abstractInst).n.sons[i].sym 
-    case putArgInto(arg, formal.typ)
-    of paDirectMapping: 
-      IdNodeTablePut(newC.mapping, formal, arg)
-    of paFastAsgn: 
-      # generate a temporary and produce an assignment statement:
-      var temp = newTemp(c, formal.typ, formal.info)
-      addVar(v, newSymNode(temp))
-      add(result, newAsgnStmt(c, newSymNode(temp), arg.ptransNode))
-      IdNodeTablePut(newC.mapping, formal, newSymNode(temp))
-    of paVarAsgn: 
-      assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
-      InternalError(arg.info, "not implemented: pass to var parameter")
-  var body = newC.owner.ast.sons[codePos]
-  pushInfoContext(n.info)
-  inc(c.inlining)
-  add(result, transform(c, body))
-  dec(c.inlining)
-  popInfoContext()
-  popTransCon(c)
-
-proc getMagicOp(call: PNode): TMagic = 
-  if (call.sons[0].kind == nkSym) and
-      (call.sons[0].sym.kind in {skProc, skMethod, skConverter}): 
-    result = call.sons[0].sym.magic
-  else: 
-    result = mNone
-  
-proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym, 
-                container: PNode) = 
-  # gather used vars for closure generation
-  if n == nil: return 
-  case n.kind
-  of nkSym: 
-    var s = n.sym
-    var found = false
-    case s.kind
-    of skVar: found = not (sfGlobal in s.flags)
-    of skTemp, skForVar, skParam: found = true
-    else: nil
-    if found and (owner.id != s.owner.id) and
-        not IntSetContainsOrIncl(marked, s.id): 
-      incl(s.flags, sfInClosure)
-      addSon(container, copyNode(n)) # DON'T make a copy of the symbol!
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
-    nil
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
-      gatherVars(c, n.sons[i], marked, owner, container)
-  
-proc addFormalParam(routine: PSym, param: PSym) = 
-  addSon(routine.typ, param.typ)
-  addSon(routine.ast.sons[paramsPos], newSymNode(param))
-
-proc indirectAccess(a, b: PSym): PNode = 
-  # returns a^ .b as a node
-  var x = newSymNode(a)
-  var y = newSymNode(b)
-  var deref = newNodeI(nkDerefExpr, x.info)
-  deref.typ = x.typ.sons[0]
-  addSon(deref, x)
-  result = newNodeI(nkDotExpr, x.info)
-  addSon(result, deref)
-  addSon(result, y)
-  result.typ = y.typ
-
-proc transformLambda(c: PTransf, n: PNode): PNode = 
-  var marked: TIntSet
-  result = n
-  IntSetInit(marked)
-  if (n.sons[namePos].kind != nkSym): InternalError(n.info, "transformLambda")
-  var s = n.sons[namePos].sym
-  var closure = newNodeI(nkRecList, n.sons[codePos].info)
-  gatherVars(c, n.sons[codePos], marked, s, closure) 
-  # add closure type to the param list (even if closure is empty!):
-  var cl = newType(tyObject, s)
-  cl.n = closure
-  addSon(cl, nil)             # no super class
-  var p = newType(tyRef, s)
-  addSon(p, cl)
-  var param = newSym(skParam, getIdent(genPrefix & "Cl"), s)
-  param.typ = p
-  addFormalParam(s, param) 
-  # all variables that are accessed should be accessed by the new closure
-  # parameter:
-  if sonsLen(closure) > 0: 
-    var newC = newTransCon(c.transCon.owner)
-    for i in countup(0, sonsLen(closure) - 1): 
-      IdNodeTablePut(newC.mapping, closure.sons[i].sym, 
-                     indirectAccess(param, closure.sons[i].sym))
-    pushTransCon(c, newC)
-    n.sons[codePos] = transform(c, n.sons[codePos]).pnode
-    popTransCon(c)
-
-proc transformCase(c: PTransf, n: PNode): PTransNode = 
-  # removes `elif` branches of a case stmt
-  # adds ``else: nil`` if needed for the code generator
-  result = newTransNode(nkCaseStmt, n, 0)
-  var ifs = PTransNode(nil)
-  for i in 0 .. sonsLen(n)-1: 
-    var it = n.sons[i]
-    var e = transform(c, it)
-    case it.kind
-    of nkElifBranch:
-      if ifs.pnode == nil:
-        ifs = newTransNode(nkIfStmt, it.info, 0)
-      ifs.add(e)
-    of nkElse:
-      if ifs.pnode == nil: result.add(e)
-      else: ifs.add(e)
-    else:
-      result.add(e)
-  if ifs.pnode != nil:
-    var elseBranch = newTransNode(nkElse, n.info, 1)
-    elseBranch[0] = ifs
-    result.add(elseBranch)
-  elif result.Pnode.lastSon.kind != nkElse and not (
-      skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
-        {tyInt..tyInt64, tyChar, tyEnum}):
-    # fix a stupid code gen bug by normalizing: 
-    var elseBranch = newTransNode(nkElse, n.info, 1)
-    elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
-    add(result, elseBranch)
-  
-proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = 
-  result = newTransNode(n)
-  result[0] = transform(c, skipConv(n.sons[0]))
-  result[1] = transform(c, skipConv(n.sons[1]))
-  
-proc getMergeOp(n: PNode): PSym = 
-  case n.kind
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
-    if (n.sons[0].Kind == nkSym) and (n.sons[0].sym.kind == skProc) and
-        (sfMerge in n.sons[0].sym.flags): 
-      result = n.sons[0].sym
-  else: nil
-
-proc flattenTreeAux(d, a: PNode, op: PSym) = 
-  var op2 = getMergeOp(a)
-  if op2 != nil and
-      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic): 
-    for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
-  else: 
-    addSon(d, copyTree(a))
-  
-proc flattenTree(root: PNode): PNode = 
-  var op = getMergeOp(root)
-  if op != nil: 
-    result = copyNode(root)
-    addSon(result, copyTree(root.sons[0]))
-    flattenTreeAux(result, root, op)
-  else: 
-    result = root
-  
-proc transformCall(c: PTransf, n: PNode): PTransNode = 
-  var n = flattenTree(n)
-  var op = getMergeOp(n)
-  if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3): 
-    result = newTransNode(nkCall, n, 0)
-    add(result, transform(c, n.sons[0]))
-    var j = 1
-    while j < sonsLen(n): 
-      var a = n.sons[j]
-      inc(j)
-      if isConstExpr(a): 
-        while (j < sonsLen(n)) and isConstExpr(n.sons[j]): 
-          a = evalOp(op.magic, n, a, n.sons[j], nil)
-          inc(j)
-      add(result, transform(c, a))
-    if len(result) == 2: result = result[1]
-  elif (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skMethod): 
-    # use the dispatcher for the call:
-    result = methodCall(transformSons(c, n).pnode).ptransNode
-  else:
-    result = transformSons(c, n)
-
-proc transform(c: PTransf, n: PNode): PTransNode = 
-  if n == nil: return
-  case n.kind
-  of nkSym: 
-    return transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
-    # nothing to be done for leaves:
-    result = PTransNode(n)
-  of nkBracketExpr: 
-    result = transformArrayAccess(c, n)
-  of nkLambda: 
-    when false: result = transformLambda(c, n)
-  of nkForStmt: 
-    result = transformFor(c, n)
-  of nkCaseStmt: 
-    result = transformCase(c, n)
-  of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: 
-    if n.sons[genericParamsPos] == nil: 
-      n.sons[codePos] = PNode(transform(c, n.sons[codePos]))
-      if n.kind == nkMethodDef: methodDef(n.sons[namePos].sym)
-    result = PTransNode(n)
-  of nkContinueStmt:
-    result = PTransNode(newNode(nkBreakStmt))
-    var labl = c.blockSyms[c.blockSyms.high]
-    add(result, PTransNode(newSymNode(labl)))
-  of nkWhileStmt: 
-    result = newTransNode(n)
-    result[0] = transform(c, n.sons[0])
-    result[1] = transformLoopBody(c, n.sons[1])
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
-    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 = transformSons(c, n)
-    if isConstExpr(PNode(result).sons[0]): 
-      # ensure that e.g. discard "some comment" gets optimized away completely:
-      result = PTransNode(newNode(nkCommentStmt))
-  of nkCommentStmt, nkTemplateDef: 
-    return n.ptransNode
-  of nkConstSection: 
-    # do not replace ``const c = 3`` with ``const 3 = 3``
-    return n.ptransNode                    
-  of nkVarSection: 
-    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)
-  else:
-    result = transformSons(c, n)
-  var cnst = getConstExpr(c.module, PNode(result))
-  if cnst != nil: 
-    result = PTransNode(cnst) # do not miss an optimization
- 
-proc processTransf(context: PPassContext, n: PNode): PNode = 
-  var c = PTransf(context)
-  pushTransCon(c, newTransCon(getCurrOwner(c)))
-  result = PNode(transform(c, n))
-  popTransCon(c)
-
-proc openTransf(module: PSym, filename: string): PPassContext = 
-  var n: PTransf
-  new(n)
-  n.blocksyms = @[]
-  n.module = module
-  result = n
-
-proc transfPass(): TPass = 
-  initPass(result)
-  result.open = openTransf
-  result.process = processTransf
-  result.close = processTransf # we need to process generics too!
-