summary refs log tree commit diff stats
path: root/compiler/transf.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/transf.nim')
-rwxr-xr-xcompiler/transf.nim98
1 files changed, 15 insertions, 83 deletions
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 12117f62a..be8f7aeb5 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -15,6 +15,7 @@
 # * performes contant folding
 # * converts "continue" to "break"
 # * introduces method dispatchers
+# * performs lambda lifting for closure support
 
 import 
   intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, 
@@ -45,7 +46,8 @@ type
     transCon: PTransCon      # top of a TransCon stack
     inlining: int            # > 0 if we are in inlining context (copy vars)
     blocksyms: seq[PSym]
-  
+    procToEnv: TIdTable      # mapping from a proc to its generated explicit
+                             # 'env' var (for closure generation)
   PTransf = ref TTransfContext
 
 proc newTransNode(a: PNode): PTransNode {.inline.} = 
@@ -354,6 +356,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
     if n.sons[0].kind == a or n.sons[0].kind == b:
       # addr ( deref ( x )) --> x
       result = PTransNode(n.sons[0].sons[0])
+
+include lambdalifting
   
 proc transformConv(c: PTransf, n: PNode): PTransNode = 
   # numeric types need range checks:
@@ -427,6 +431,11 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result[0] = transform(c, n.sons[1])
     else: 
       result = transform(c, n.sons[1])
+  of tyProc:
+    if dest.callConv == ccClosure and source.callConv == ccDefault:
+      result = generateThunk(c, n.sons[1], dest).ptransnode
+    else:
+      result = transformSons(c, n)    
   of tyGenericParam, tyOrdinal: 
     result = transform(c, n.sons[1])
     # happens sometimes for generated assignments, etc.
@@ -502,77 +511,12 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   popTransCon(c)
   #echo "transformed: ", renderTree(n)
   
-
 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
-  case n.kind
-  of nkSym:
-    var s = n.sym
-    var found = false
-    case s.kind
-    of skVar, skLet: found = sfGlobal notin s.flags
-    of skTemp, skForVar, skParam, skResult: found = true
-    else: nil
-    if found and owner.id != s.owner.id and not ContainsOrIncl(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(nkHiddenDeref, 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 = initIntSet()
-  result = n
-  if n.sons[namePos].kind != nkSym: InternalError(n.info, "transformLambda")
-  var s = n.sons[namePos].sym
-  var closure = newNodeI(nkRecList, n.info)
-  var body = s.getBody
-  gatherVars(c, body, 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[bodyPos] = transform(c, body).pnode
-    popTransCon(c)
 
 proc transformCase(c: PTransf, n: PNode): PTransNode = 
   # removes `elif` branches of a case stmt
@@ -670,23 +614,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
     # nothing to be done for leaves:
     result = PTransNode(n)
-  of nkBracketExpr: 
-    result = transformArrayAccess(c, n)
-  of nkLambda: 
-    var s = n.sons[namePos].sym
-    n.sons[bodyPos] = PNode(transform(c, s.getBody))
-    result = PTransNode(n)
-    when false: result = transformLambda(c, n)
-  of nkForStmt: 
-    result = transformFor(c, n)
-  of nkCaseStmt: 
-    result = transformCase(c, n)
-  of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkConverterDef: 
-    if n.sons[genericParamsPos].kind == nkEmpty: 
-      var s = n.sons[namePos].sym
-      n.sons[bodyPos] = PNode(transform(c, s.getBody))
-      if n.kind == nkMethodDef: methodDef(s, false)
-    result = PTransNode(n)
+  of nkBracketExpr: result = transformArrayAccess(c, n)
+  of procDefs: result = transformProc(c, n)
+  of nkForStmt: result = transformFor(c, n)
+  of nkCaseStmt: result = transformCase(c, n)
   of nkContinueStmt:
     result = PTransNode(newNode(nkBreakStmt))
     var labl = c.blockSyms[c.blockSyms.high]
@@ -748,6 +679,7 @@ proc openTransf(module: PSym, filename: string): PPassContext =
   new(n)
   n.blocksyms = @[]
   n.module = module
+  initIdTable(n.procToEnv)
   result = n
 
 proc openTransfCached(module: PSym, filename: string,