diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 9784b21bbb..e9d7673bbd 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -578,6 +578,7 @@ proc closureSetup(p: BProc, prc: PSym) = if prc.typ.callConv != ccClosure: return # prc.ast[paramsPos].last contains the type we're after: var env = lastSon(prc.ast[paramsPos]).sym + #echo "created environment: ", env.id, " for ", prc.name.s assignLocalVar(p, env) # generate cast assignment: appcg(p, cpsStmts, "$1 = ($2) ClEnv;$n", rdLoc(env.loc), diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 70db9334e8..83885029ab 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,8 +10,9 @@ # This include file implements lambda lifting for the transformator. const - procDefs = {nkLambda, nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, + declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkConverterDef} + procDefs = {nkLambda} + declarativeDefs proc indirectAccess(a, b: PSym, info: TLineInfo): PNode = # returns a[].b as a node @@ -47,17 +48,16 @@ proc captureToTuple(cap: TCapture, owner: PSym): PType = addSon(result.n, newSymNode(field)) addSon(result, typ) +proc interestingVar(s: PSym): bool {.inline.} = + result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and + sfGlobal notin s.flags + proc gatherVars(c: PTransf, n: PNode, outerProc: PSym, cap: var TCapture) = # gather used vars for closure generation into 'cap' 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 outerProc.id == s.owner.id: + if interestingVar(s) and outerProc.id == s.owner.id: #echo "captured: ", s.name.s Capture(cap, s) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil @@ -70,37 +70,34 @@ proc replaceVars(c: PTransf, n: PNode, outerProc, env: PSym) = let a = n.sons[i] if a.kind == nkSym: let s = a.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 outerProc.id == s.owner.id: + if interestingVar(s) and outerProc == s.owner: # access through the closure param: n.sons[i] = indirectAccess(env, s, n.info) else: replaceVars(c, a, outerProc, env) -proc addFormalParam(routine: PType, param: PSym) = - addSon(routine, param.typ) - addSon(routine.n, newSymNode(param)) - -proc addFormalParam(routine: PSym, param: PSym) = - #addFormalParam(routine.typ, param) - addSon(routine.ast.sons[paramsPos], newSymNode(param)) +proc addHiddenParam(routine: PSym, param: PSym) = + var params = routine.ast.sons[paramsPos] + let L = params.len-1 + if L >= 0: + # update if we already added a hidden parameter: + if params.sons[L].kind == nkSym and params.sons[L].sym.kind == skTemp: + params.sons[L].sym = param + return + addSon(params, newSymNode(param)) + #echo "produced environment: ", param.id, " for ", routine.name.s proc isInnerProc(s, outerProc: PSym): bool {.inline.} = result = s.kind in {skProc, skMacro, skIterator, skMethod, skConverter} and - s.owner.id == outerProc.id and not isGenericRoutine(s) and - s.typ.callConv == ccClosure + s.owner == outerProc and not isGenericRoutine(s) + #s.typ.callConv == ccClosure proc searchForInnerProcs(c: PTransf, n: PNode, outerProc: PSym, cap: var TCapture) = case n.kind of nkSym: - let s = n.sym - if isInnerProc(s, outerProc): - gatherVars(c, s.getBody, outerProc, cap) + if isInnerProc(n.sym, outerProc): + gatherVars(c, n.sym.getBody, outerProc, cap) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: nil else: for i in 0.. 0 if we are in inlining context (copy vars) + nestedProcs: int # > 0 if we are in a nested proc blocksyms: seq[PSym] - procToEnv: TIdTable # mapping from a proc to its generated explicit - # 'env' var (for closure generation) + transformedInnerProcs: TIntSet PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -616,7 +616,16 @@ proc transform(c: PTransf, n: PNode): PTransNode = # nothing to be done for leaves: result = PTransNode(n) of nkBracketExpr: result = transformArrayAccess(c, n) - of procDefs: result = transformProc(c, n) + of procDefs: + if c.nestedProcs == 0: + inc c.nestedProcs + result = transformProc(c, n) + dec c.nestedProcs + else: + result = PTransNode(n) + if n.sons[namePos].kind == nkSym: + let x = transformSym(c, n.sons[namePos]) + if x.pnode.kind == nkClosure: result = x of nkForStmt: result = transformFor(c, n) of nkCaseStmt: result = transformCase(c, n) of nkContinueStmt: @@ -680,7 +689,7 @@ proc openTransf(module: PSym, filename: string): PPassContext = new(n) n.blocksyms = @[] n.module = module - initIdTable(n.procToEnv) + n.transformedInnerProcs = initIntSet() result = n proc openTransfCached(module: PSym, filename: string, diff --git a/todo.txt b/todo.txt index 7a5ec60544..1bf562db74 100755 --- a/todo.txt +++ b/todo.txt @@ -2,9 +2,9 @@ version 0.8.14 ============== - implement closures - - test evals.nim with closures + - fix evals.nim with closures - deactivate lambda lifting for JS backend - - Test capture of for loop vars; test generics; test recursion + - Test capture of for loop vars; test generics; - test constant closures - 'closureEnv' magic for easy interfacing with C