summary refs log tree commit diff stats
path: root/nim/transf.pas
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
committerAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
commitcd292568d775d55d9abb51e962882ecda12c03a9 (patch)
tree85451f0e1f17dc0463350915f12bdd0a82a73455 /nim/transf.pas
parent46c41e43690cba9bc1caff6a994bb6915df8a1b7 (diff)
downloadNim-cd292568d775d55d9abb51e962882ecda12c03a9.tar.gz
big repo cleanup
Diffstat (limited to 'nim/transf.pas')
-rwxr-xr-xnim/transf.pas964
1 files changed, 0 insertions, 964 deletions
diff --git a/nim/transf.pas b/nim/transf.pas
deleted file mode 100755
index a0f07d51d..000000000
--- a/nim/transf.pas
+++ /dev/null
@@ -1,964 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2009 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-unit transf;
-
-// 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
-// * introduces nkHiddenDeref, nkHiddenSubConv, etc.
-// * introduces method dispatchers
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  sysutils, nsystem, charsets, strutils,
-  lists, options, ast, astalgo, trees, treetab, evals,
-  msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys, cgmeth;
-
-const
-  genPrefix = ':tmp'; // prefix for generated names
-  
-function transfPass(): TPass;
-
-implementation
-
-type
-  PTransCon = ^TTransCon;
-  TTransCon = record   // part of TContext; stackable
-    mapping: TIdNodeTable; // mapping from symbols to nodes
-    owner: PSym;        // current owner
-    forStmt: PNode;    // current for stmt
-    next: PTransCon;   // for stacking
-  end;
-  
-  TTransfContext = object(passes.TPassContext)
-    module: PSym;
-    transCon: PTransCon; // top of a TransCon stack
-  end;
-  PTransf = ^TTransfContext;
-
-function newTransCon(): PTransCon;
-begin
-  new(result);
-{@ignore}
-  fillChar(result^, sizeof(result^), 0);
-{@emit}
-  initIdNodeTable(result.mapping);
-end;
-
-procedure pushTransCon(c: PTransf; t: PTransCon);
-begin
-  t.next := c.transCon;
-  c.transCon := t;
-end;
-
-procedure popTransCon(c: PTransf);
-begin
-  if (c.transCon = nil) then InternalError('popTransCon');
-  c.transCon := c.transCon.next;
-end;
-
-// ------------ helpers -----------------------------------------------------
-
-function getCurrOwner(c: PTransf): PSym;
-begin
-  if c.transCon <> nil then result := c.transCon.owner
-  else result := c.module;
-end;
-
-function newTemp(c: PTransf; typ: PType; const info: TLineInfo): PSym;
-begin
-  result := newSym(skTemp, getIdent(genPrefix), getCurrOwner(c));
-  result.info := info;
-  result.typ := skipTypes(typ, {@set}[tyGenericInst]);
-  include(result.flags, sfFromGeneric);
-end;
-
-// --------------------------------------------------------------------------
-
-function transform(c: PTransf; n: PNode): PNode; forward;
-
-(*
-
-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)
-*)
-
-function newAsgnStmt(c: PTransf; le, ri: PNode): PNode;
-begin
-  result := newNodeI(nkFastAsgn, ri.info);
-  addSon(result, le);
-  addSon(result, ri);
-end;
-
-function transformSym(c: PTransf; n: PNode): PNode;
-var
-  tc: PTransCon;
-  b: PNode;
-begin
-  if (n.kind <> nkSym) then internalError(n.info, 'transformSym');
-  tc := c.transCon;
-  if sfBorrow in n.sym.flags then begin
-    // simply exchange the symbol:
-    b := n.sym.ast.sons[codePos];
-    if b.kind <> nkSym then 
-      internalError(n.info, 'wrong AST for borrowed symbol');
-    b := newSymNode(b.sym);
-    b.info := n.info;
-  end
-  else 
-    b := n;
-  //writeln('transformSym', n.sym.id : 5);
-  while tc <> nil do begin
-    result := IdNodeTableGet(tc.mapping, b.sym);
-    if result <> nil then exit;
-    //write('not found in: ');
-    //writeIdNodeTable(tc.mapping);
-    tc := tc.next
-  end;
-  result := b;
-  case b.sym.kind of
-    skConst, skEnumField: begin // BUGFIX: skEnumField was missing
-      if not (skipTypes(b.sym.typ, abstractInst).kind in ConstantDataTypes) then begin
-        result := getConstExpr(c.module, b);
-        if result = nil then InternalError(b.info, 'transformSym: const');
-      end
-    end
-    else begin end
-  end
-end;
-
-procedure transformContinueAux(c: PTransf; n: PNode; labl: PSym;
-                               var counter: int);
-var
-  i: int;
-begin
-  if n = nil then exit;
-  case n.kind of
-    nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: begin end;
-    nkContinueStmt: begin
-      n.kind := nkBreakStmt;
-      addSon(n, newSymNode(labl));
-      inc(counter);
-    end;
-    else begin
-      for i := 0 to sonsLen(n)-1 do
-        transformContinueAux(c, n.sons[i], labl, counter);
-    end
-  end
-end;
-
-function transformContinue(c: PTransf; n: PNode): PNode;
-// we transform the continue statement into a block statement
-var
-  i, counter: int;
-  x: PNode;
-  labl: PSym;
-begin
-  result := n;
-  for i := 0 to sonsLen(n)-1 do
-    result.sons[i] := transform(c, n.sons[i]);
-  counter := 0;
-  labl := newSym(skLabel, nil, getCurrOwner(c));
-  labl.name := getIdent(genPrefix +{&} ToString(labl.id));
-  labl.info := result.info;
-  transformContinueAux(c, result, labl, counter);
-  if counter > 0 then begin
-    x := newNodeI(nkBlockStmt, result.info);
-    addSon(x, newSymNode(labl));
-    addSon(x, result);
-    result := x
-  end
-end;
-
-function skipConv(n: PNode): PNode;
-begin
-  case n.kind of
-    nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange,
-    nkChckRangeF, nkChckRange64:
-      result := n.sons[0];
-    nkHiddenStdConv, nkHiddenSubConv, nkConv: result := n.sons[1];
-    else result := n
-  end
-end;
-
-function newTupleAccess(tup: PNode; i: int): PNode;
-var
-  lit: PNode;
-begin
-  result := newNodeIT(nkBracketExpr, tup.info, tup.typ.sons[i]);
-  addSon(result, copyTree(tup));
-  lit := newNodeIT(nkIntLit, tup.info, getSysType(tyInt));
-  lit.intVal := i;
-  addSon(result, lit);
-end;
-
-procedure unpackTuple(c: PTransf; n, father: PNode);
-var
-  i: int;
-begin
-  // XXX: BUG: what if `n` is an expression with side-effects?
-  for i := 0 to sonsLen(n)-1 do begin
-    addSon(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
-           transform(c, newTupleAccess(n, i))));
-  end
-end;
-
-function transformYield(c: PTransf; n: PNode): PNode;
-var
-  e: PNode;
-  i: int;
-begin
-  result := newNodeI(nkStmtList, n.info);
-  e := n.sons[0];
-  if skipTypes(e.typ, {@set}[tyGenericInst]).kind = tyTuple then begin
-    e := skipConv(e);
-    if e.kind = nkPar then begin
-      for i := 0 to sonsLen(e)-1 do begin
-        addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
-               transform(c, copyTree(e.sons[i]))));
-      end
-    end
-    else 
-      unpackTuple(c, e, result);
-  end
-  else begin
-    e := transform(c, copyTree(e));
-    addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], e));
-  end;
-  // add body of the for loop:
-  addSon(result, transform(c, lastSon(c.transCon.forStmt)));
-end;
-
-function inlineIter(c: PTransf; n: PNode): PNode;
-var
-  i, j, L: int;
-  it: PNode;
-  newVar: PSym;
-begin
-  result := n;
-  if n = nil then exit;
-  case n.kind of
-    nkEmpty..nkNilLit: begin
-      result := transform(c, copyTree(n));
-    end;
-    nkYieldStmt: result := transformYield(c, n);
-    nkVarSection: begin
-      result := copyTree(n);
-      for i := 0 to sonsLen(result)-1 do begin
-        it := result.sons[i];
-        if it.kind = nkCommentStmt then continue;
-        if it.kind = nkIdentDefs then begin
-          if (it.sons[0].kind <> nkSym) then
-            InternalError(it.info, 'inlineIter');
-          newVar := copySym(it.sons[0].sym);
-          include(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));
-          it.sons[0] := newSymNode(newVar);
-          it.sons[2] := transform(c, it.sons[2]);
-        end
-        else begin
-          if it.kind <> nkVarTuple then
-            InternalError(it.info, 'inlineIter: not nkVarTuple');
-          L := sonsLen(it);
-          for j := 0 to L-3 do begin
-            newVar := copySym(it.sons[j].sym);
-            include(newVar.flags, sfFromGeneric);
-            newVar.owner := getCurrOwner(c);
-            IdNodeTablePut(c.transCon.mapping, it.sons[j].sym,
-                           newSymNode(newVar));
-            it.sons[j] := newSymNode(newVar);
-          end;
-          assert(it.sons[L-2] = nil);
-          it.sons[L-1] := transform(c, it.sons[L-1]);
-        end
-      end
-    end
-    else begin
-      result := copyNode(n);
-      for i := 0 to sonsLen(n)-1 do addSon(result, inlineIter(c, n.sons[i]));
-      result := transform(c, result);
-    end
-  end
-end;
-
-procedure addVar(father, v: PNode);
-var
-  vpart: PNode;
-begin
-  vpart := newNodeI(nkIdentDefs, v.info);
-  addSon(vpart, v);
-  addSon(vpart, nil);
-  addSon(vpart, nil);
-  addSon(father, vpart);
-end;
-
-function transformAddrDeref(c: PTransf; n: PNode; a, b: TNodeKind): PNode;
-var
-  m: PNode;
-begin
-  case n.sons[0].kind of
-    nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange,
-    nkChckRangeF, nkChckRange64: begin
-      m := n.sons[0].sons[0];
-      if (m.kind = a) or (m.kind = b) then begin
-        // addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x)
-        n.sons[0].sons[0] := m.sons[0];
-        result := transform(c, n.sons[0]);
-        exit
-      end
-    end;
-    nkHiddenStdConv, nkHiddenSubConv, nkConv: begin
-      m := n.sons[0].sons[1];
-      if (m.kind = a) or (m.kind = b) then begin
-        // addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-        n.sons[0].sons[1] := m.sons[0];
-        result := transform(c, n.sons[0]);
-        exit
-      end
-    end;
-    else begin
-      if (n.sons[0].kind = a) or (n.sons[0].kind = b) then begin
-        // addr ( deref ( x )) --> x
-        result := transform(c, n.sons[0].sons[0]);
-        exit
-      end
-    end
-  end;
-  n.sons[0] := transform(c, n.sons[0]);
-  result := n;
-end;
-
-function transformConv(c: PTransf; n: PNode): PNode;
-var
-  source, dest: PType;
-  diff: int;
-begin
-  n.sons[1] := transform(c, n.sons[1]);
-  result := n;
-  // numeric types need range checks:
-  dest := skipTypes(n.typ, abstractVarRange);
-  source := skipTypes(n.sons[1].typ, abstractVarRange);
-  case dest.kind of
-    tyInt..tyInt64, tyEnum, tyChar, tyBool: begin
-      if (firstOrd(dest) <= firstOrd(source)) and
-          (lastOrd(source) <= lastOrd(dest)) then begin
-        // BUGFIX: simply leave n as it is; we need a nkConv node,
-        // but no range check:
-        result := n;
-      end
-      else begin // generate a range check:
-        if (dest.kind = tyInt64) or (source.kind = tyInt64) then
-          result := newNodeIT(nkChckRange64, n.info, n.typ)
-        else
-          result := newNodeIT(nkChckRange, n.info, n.typ);
-        dest := skipTypes(n.typ, abstractVar);
-        addSon(result, n.sons[1]);
-        addSon(result, newIntTypeNode(nkIntLit, firstOrd(dest), source));
-        addSon(result, newIntTypeNode(nkIntLit,  lastOrd(dest), source));
-      end
-    end;
-    tyFloat..tyFloat128: begin
-      if skipTypes(n.typ, abstractVar).kind = tyRange then begin
-        result := newNodeIT(nkChckRangeF, n.info, n.typ);
-        dest := skipTypes(n.typ, abstractVar);
-        addSon(result, n.sons[1]);
-        addSon(result, copyTree(dest.n.sons[0]));
-        addSon(result, copyTree(dest.n.sons[1]));
-      end
-    end;
-    tyOpenArray: begin
-      result := newNodeIT(nkPassAsOpenArray, n.info, n.typ);
-      addSon(result, n.sons[1]);
-    end;
-    tyCString: begin
-      if source.kind = tyString then begin
-        result := newNodeIT(nkStringToCString, n.info, n.typ);
-        addSon(result, n.sons[1]);
-      end;
-    end;
-    tyString: begin
-      if source.kind = tyCString then begin
-        result := newNodeIT(nkCStringToString, n.info, n.typ);
-        addSon(result, n.sons[1]);
-      end;
-    end;
-    tyRef, tyPtr: begin
-      dest := skipTypes(dest, abstractPtrs);
-      source := skipTypes(source, abstractPtrs);
-      if source.kind = tyObject then begin
-        diff := inheritanceDiff(dest, source);
-        if diff < 0 then begin
-          result := newNodeIT(nkObjUpConv, n.info, n.typ);
-          addSon(result, n.sons[1]);
-        end
-        else if diff > 0 then begin
-          result := newNodeIT(nkObjDownConv, n.info, n.typ);
-          addSon(result, n.sons[1]);
-        end
-        else result := n.sons[1];
-      end
-    end;
-    // conversions between different object types:
-    tyObject: begin
-      diff := inheritanceDiff(dest, source);
-      if diff < 0 then begin
-        result := newNodeIT(nkObjUpConv, n.info, n.typ);
-        addSon(result, n.sons[1]);
-      end
-      else if diff > 0 then begin
-        result := newNodeIT(nkObjDownConv, n.info, n.typ);
-        addSon(result, n.sons[1]);
-      end
-      else result := n.sons[1];
-    end; (*
-    tyArray, tySeq: begin
-      if skipGeneric(dest
-    end; *)
-    tyGenericParam, tyOrdinal: result := n.sons[1];
-      // happens sometimes for generated assignments, etc.
-    else begin end
-  end;
-end;
-
-function skipPassAsOpenArray(n: PNode): PNode;
-begin
-  result := n;
-  while result.kind = nkPassAsOpenArray do result := result.sons[0]
-end;
-
-type 
-  TPutArgInto = (paDirectMapping, paFastAsgn, paVarAsgn);
-
-function putArgInto(arg: PNode; formal: PType): TPutArgInto;
-// This analyses how to treat the mapping "formal <-> arg" in an
-// inline context.
-var
-  i: int;
-begin
-  if skipTypes(formal, abstractInst).kind = tyOpenArray then begin
-    result := paDirectMapping; // XXX really correct?
-    // what if ``arg`` has side-effects?
-    exit
-  end;
-  case arg.kind of
-    nkEmpty..nkNilLit: result := paDirectMapping;
-    nkPar, nkCurly, nkBracket: begin
-      result := paFastAsgn;
-      for i := 0 to sonsLen(arg)-1 do 
-        if putArgInto(arg.sons[i], formal) <> paDirectMapping then
-          exit;
-      result := paDirectMapping;
-    end;
-    else begin
-      if skipTypes(formal, abstractInst).kind = tyVar then
-        result := paVarAsgn
-      else
-        result := paFastAsgn
-    end
-  end
-end;
-
-function transformFor(c: PTransf; n: PNode): PNode;
-// generate access statements for the parameters (unless they are constant)
-// put mapping from formal parameters to actual parameters
-var
-  i, len: int;
-  call, v, body, arg: PNode;
-  newC: PTransCon;
-  temp, formal: PSym;
-begin
-  if (n.kind <> nkForStmt) then InternalError(n.info, 'transformFor');
-  result := newNodeI(nkStmtList, n.info);
-  len := sonsLen(n);
-  n.sons[len-1] := transformContinue(c, n.sons[len-1]);
-  v := newNodeI(nkVarSection, n.info);
-  for i := 0 to len-3 do addVar(v, copyTree(n.sons[i])); // declare new vars
-  addSon(result, v);
-  newC := newTransCon();
-  call := n.sons[len-2];
-  if (call.kind <> nkCall) or (call.sons[0].kind <> nkSym) then
-    InternalError(call.info, 'transformFor');
-  newC.owner := call.sons[0].sym;
-  newC.forStmt := n;
-  if (newC.owner.kind <> skIterator) then 
-    InternalError(call.info, 'transformFor');
-  // generate access statements for the parameters (unless they are constant)
-  pushTransCon(c, newC);
-  for i := 1 to sonsLen(call)-1 do begin
-    arg := skipPassAsOpenArray(transform(c, call.sons[i]));
-    formal := skipTypes(newC.owner.typ, abstractInst).n.sons[i].sym;
-    //if IdentEq(newc.Owner.name, 'items') then 
-    //  liMessage(arg.info, warnUser, 'items: ' + nodeKindToStr[arg.kind]);
-    case putArgInto(arg, formal.typ) of
-      paDirectMapping: IdNodeTablePut(newC.mapping, formal, arg);
-      paFastAsgn: begin
-        // generate a temporary and produce an assignment statement:
-        temp := newTemp(c, formal.typ, formal.info);
-        addVar(v, newSymNode(temp));
-        addSon(result, newAsgnStmt(c, newSymNode(temp), arg));
-        IdNodeTablePut(newC.mapping, formal, newSymNode(temp));
-      end;
-      paVarAsgn: begin
-        assert(skipTypes(formal.typ, abstractInst).kind = tyVar);
-        InternalError(arg.info, 'not implemented: pass to var parameter');
-      end;
-    end;
-  end;
-  body := newC.owner.ast.sons[codePos];
-  pushInfoContext(n.info);
-  addSon(result, inlineIter(c, body));
-  popInfoContext();
-  popTransCon(c);
-end;
-
-function getMagicOp(call: PNode): TMagic;
-begin
-  if (call.sons[0].kind = nkSym)
-  and (call.sons[0].sym.kind in [skProc, skMethod, skConverter]) then
-    result := call.sons[0].sym.magic
-  else
-    result := mNone
-end;
-
-procedure gatherVars(c: PTransf; n: PNode; var marked: TIntSet;
-                     owner: PSym; container: PNode);
-// gather used vars for closure generation
-var
-  i: int;
-  s: PSym;
-  found: bool;
-begin
-  if n = nil then exit;
-  case n.kind of
-    nkSym: begin
-      s := n.sym;
-      found := false;
-      case s.kind of
-        skVar: found := not (sfGlobal in s.flags);
-        skTemp, skForVar, skParam: found := true;
-        else begin end;
-      end;
-      if found and (owner.id <> s.owner.id)
-      and not IntSetContainsOrIncl(marked, s.id) then begin
-        include(s.flags, sfInClosure);
-        addSon(container, copyNode(n)); // DON'T make a copy of the symbol!
-      end
-    end;
-    nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: begin end;
-    else begin
-      for i := 0 to sonsLen(n)-1 do
-        gatherVars(c, n.sons[i], marked, owner, container);
-    end
-  end
-end;
-
-(*
-  # example:
-  proc map(f: proc (x: int): int {.closure}, a: seq[int]): seq[int] =
-    result = @[]
-    for elem in a:
-      add result, f(a)
-
-  proc addList(a: seq[int], y: int): seq[int] =
-    result = map(lambda (x: int): int = return x + y, a)
-
-  should generate -->
-
-  proc map(f: proc(x: int): int, closure: pointer,
-           a: seq[int]): seq[int] =
-    result = @[]
-    for elem in a:
-      add result, f(a, closure)
-
-  type
-    PMyClosure = ref object
-      y: var int
-
-  proc myLambda(x: int, closure: pointer) =
-    var cl = cast[PMyClosure](closure)
-    return x + cl.y
-
-  proc addList(a: seq[int], y: int): seq[int] =
-    var
-      cl: PMyClosure
-    new(cl)
-    cl.y = y
-    result = map(myLambda, cast[pointer](cl), a)
-
-
-  or (but this is not easier and not binary compatible with C!) -->
-
-  type
-    PClosure = ref object of TObject
-      f: proc (x: int, c: PClosure): int
-
-  proc map(f: PClosure, a: seq[int]): seq[int] =
-    result = @[]
-    for elem in a:
-      add result, f.f(a, f)
-
-  type
-    PMyClosure = ref object of PClosure
-      y: var int
-
-  proc myLambda(x: int, cl: PMyClosure) =
-    return x + cl.y
-
-  proc addList(a: seq[int], y: int): seq[int] =
-    var
-      cl: PMyClosure
-    new(cl)
-    cl.y = y
-    cl.f = myLambda
-    result = map(cl, a)
-*)
-
-procedure addFormalParam(routine: PSym; param: PSym);
-begin
-  addSon(routine.typ, param.typ);
-  addSon(routine.ast.sons[paramsPos], newSymNode(param));
-end;
-
-function indirectAccess(a, b: PSym): PNode;
-// returns a^ .b as a node
-var
-  x, y, deref: PNode;
-begin
-  x := newSymNode(a);
-  y := newSymNode(b);
-  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;
-end;
-
-function transformLambda(c: PTransf; n: PNode): PNode;
-var
-  marked: TIntSet;
-  closure: PNode;
-  s, param: PSym;
-  cl, p: PType;
-  i: int;
-  newC: PTransCon;
-begin
-  result := n;
-  IntSetInit(marked);
-  if (n.sons[namePos].kind <> nkSym) then
-    InternalError(n.info, 'transformLambda');
-  s := n.sons[namePos].sym;
-  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!):
-  cl := newType(tyObject, s);
-  cl.n := closure;
-  addSon(cl, nil); // no super class
-  p := newType(tyRef, s);
-  addSon(p, cl);
-  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 then begin
-    newC := newTransCon();
-    for i := 0 to sonsLen(closure)-1 do begin
-      IdNodeTablePut(newC.mapping, closure.sons[i].sym,
-                     indirectAccess(param, closure.sons[i].sym))
-    end;
-    pushTransCon(c, newC);
-    n.sons[codePos] := transform(c, n.sons[codePos]);
-    popTransCon(c);
-  end;
-  // Generate code to allocate and fill the closure. This has to be done in
-  // the outer routine!
-end;
-
-function transformCase(c: PTransf; n: PNode): PNode;
-// removes `elif` branches of a case stmt
-// adds ``else: nil`` if needed for the code generator
-var
-  len, i, j: int;
-  ifs, elsen: PNode;
-begin
-  len := sonsLen(n);
-  i := len-1;
-  if n.sons[i].kind = nkElse then dec(i);
-  if n.sons[i].kind = nkElifBranch then begin
-    while n.sons[i].kind = nkElifBranch do dec(i);
-    if (n.sons[i].kind <> nkOfBranch) then 
-      InternalError(n.sons[i].info, 'transformCase');
-    ifs := newNodeI(nkIfStmt, n.sons[i+1].info);
-    elsen := newNodeI(nkElse, ifs.info);
-    for j := i+1 to len-1 do addSon(ifs, n.sons[j]);
-    setLength(n.sons, i+2);
-    addSon(elsen, ifs);
-    n.sons[i+1] := elsen;
-  end  
-  else if (n.sons[len-1].kind <> nkElse) and 
-           not (skipTypes(n.sons[0].Typ, abstractVarRange).Kind in
-               [tyInt..tyInt64, tyChar, tyEnum]) then begin
-    //MessageOut(renderTree(n));
-    elsen := newNodeI(nkElse, n.info);
-    addSon(elsen, newNodeI(nkNilLit, n.info));
-    addSon(n, elsen)
-  end;
-  result := n;
-  for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]);
-end;
-
-function transformArrayAccess(c: PTransf; n: PNode): PNode;
-var
-  i: int;
-begin
-  result := copyTree(n);
-  result.sons[0] := skipConv(result.sons[0]);
-  result.sons[1] := skipConv(result.sons[1]);
-  for i := 0 to sonsLen(result)-1 do
-    result.sons[i] := transform(c, result.sons[i]);
-end;
-
-function getMergeOp(n: PNode): PSym;
-begin
-  result := nil;
-  case n.kind of
-    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
-    nkCallStrLit: begin
-      if (n.sons[0].Kind = nkSym) and (n.sons[0].sym.kind = skProc) 
-      and (sfMerge in n.sons[0].sym.flags) then 
-        result := n.sons[0].sym;
-    end
-    else begin end
-  end
-end;
-
-procedure flattenTreeAux(d, a: PNode; op: PSym);
-var
-  i: int;
-  op2: PSym;
-begin
-  op2 := getMergeOp(a);
-  if (op2 <> nil) and ((op2.id = op.id) 
-                   or (op.magic <> mNone) and (op2.magic = op.magic)) then
-    for i := 1 to sonsLen(a)-1 do
-      flattenTreeAux(d, a.sons[i], op)
-  else
-    // a is a "leaf", so add it:
-    addSon(d, copyTree(a))
-end;
-
-function flattenTree(root: PNode): PNode;
-var
-  op: PSym;
-begin
-  op := getMergeOp(root);
-  if op <> nil then begin
-    result := copyNode(root);
-    addSon(result, copyTree(root.sons[0]));
-    flattenTreeAux(result, root, op)
-  end
-  else 
-    result := root
-end;
-
-function transformCall(c: PTransf; n: PNode): PNode;
-var
-  i, j: int;
-  m, a: PNode;
-  op: PSym;
-begin
-  result := flattenTree(n);
-  for i := 0 to sonsLen(result)-1 do
-    result.sons[i] := transform(c, result.sons[i]);
-  op := getMergeOp(result);
-  if (op <> nil) and (op.magic <> mNone) and (sonsLen(result) >= 3) then begin
-    m := result;
-    result := newNodeIT(nkCall, m.info, m.typ);
-    addSon(result, copyTree(m.sons[0]));
-    j := 1;
-    while j < sonsLen(m) do begin
-      a := m.sons[j];
-      inc(j);
-      if isConstExpr(a) then 
-        while (j < sonsLen(m)) and isConstExpr(m.sons[j]) do begin
-          a := evalOp(op.magic, m, a, m.sons[j], nil);
-          inc(j)
-        end;
-      addSon(result, a);
-    end;
-    if sonsLen(result) = 2 then
-      result := result.sons[1];
-  end
-  else if (result.sons[0].kind = nkSym)
-  and (result.sons[0].sym.kind = skMethod) then begin
-    // use the dispatcher for the call:
-    result := methodCall(result);
-  end
-  (*
-  else if result.sons[0].kind = nkSym then begin
-    // optimization still too aggressive
-    op := result.sons[0].sym;
-    if (op.magic = mNone) and (op.kind = skProc) 
-    and ([sfSideEffect, sfForward, sfNoReturn, sfImportc] * op.flags = [])
-    then begin
-      for i := 1 to sonsLen(result)-1 do
-        if not isConstExpr(result.sons[i]) then exit;
-      // compile-time evaluation:
-      a := evalConstExpr(c.module, result);
-      if (a <> nil) and (a.kind <> nkEmpty) then begin
-        messageout('evaluated at compile time: ' + rendertree(result));
-        result := a
-      end
-    end
-  end *)
-end;
-
-function transform(c: PTransf; n: PNode): PNode;
-var
-  i: int;
-  cnst: PNode;
-begin
-  result := n;
-  if n = nil then exit;
-  //if ToLinenumber(n.info) = 32 then
-  //  MessageOut(RenderTree(n));
-  case n.kind of
-    nkSym: begin
-      result := transformSym(c, n);
-      exit
-    end;
-    nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: begin
-      // nothing to be done for leaves
-    end;
-    nkBracketExpr: result := transformArrayAccess(c, n);
-    nkLambda: result := transformLambda(c, n);
-    nkForStmt: result := transformFor(c, n);
-    nkCaseStmt: result := transformCase(c, n);
-    nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: begin
-      if n.sons[genericParamsPos] = nil then begin
-        n.sons[codePos] := transform(c, n.sons[codePos]);
-        if n.kind = nkMethodDef then
-          methodDef(n.sons[namePos].sym);
-      end
-    end;
-    nkWhileStmt: begin
-      if (sonsLen(n) <> 2) then InternalError(n.info, 'transform');
-      n.sons[0] := transform(c, n.sons[0]);
-      n.sons[1] := transformContinue(c, n.sons[1]);
-    end;
-    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
-    nkCallStrLit:
-      result := transformCall(c, result);
-    nkAddr, nkHiddenAddr:
-      result := transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref);
-    nkDerefExpr, nkHiddenDeref:
-      result := transformAddrDeref(c, n, nkAddr, nkHiddenAddr);
-    nkHiddenStdConv, nkHiddenSubConv, nkConv:
-      result := transformConv(c, n);
-    nkDiscardStmt: begin
-      for i := 0 to sonsLen(n)-1 do
-        result.sons[i] := transform(c, n.sons[i]);
-      if isConstExpr(result.sons[0]) then
-        result := newNode(nkCommentStmt)
-    end;
-    nkCommentStmt, nkTemplateDef: exit;
-    nkConstSection: exit; // do not replace ``const c = 3`` with ``const 3 = 3``
-    else begin
-      for i := 0 to sonsLen(n)-1 do
-        result.sons[i] := transform(c, n.sons[i]);
-    end
-  end;
-  cnst := getConstExpr(c.module, result);
-  if cnst <> nil then result := cnst; // do not miss an optimization  
-end;
-
-function processTransf(context: PPassContext; n: PNode): PNode;
-var
-  c: PTransf;
-begin
-  c := PTransf(context);
-  result := transform(c, n);
-end;
-
-function openTransf(module: PSym; const filename: string): PPassContext;
-var
-  n: PTransf;
-begin
-  new(n);
-{@ignore}
-  fillChar(n^, sizeof(n^), 0);
-{@emit}
-  n.module := module;
-  result := n;
-end;
-
-function transfPass(): TPass;
-begin
-  initPass(result);
-  result.open := openTransf;
-  result.process := processTransf;
-  result.close := processTransf; // we need to process generics too!
-end;
-
-end.