diff options
Diffstat (limited to 'compiler/transf.nim')
-rwxr-xr-x | compiler/transf.nim | 98 |
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, |