From 325dd44e81b44814986f5d586f1934a814c1b148 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 3 Apr 2014 22:35:10 +0200 Subject: [PATCH] gensym'ed symbols work with lambda-lifting; closures produce objects instead of tuples for easier debugging --- compiler/ccgstmts.nim | 2 +- compiler/lambdalifting.nim | 72 ++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 990153fc7..311149cb3 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -138,7 +138,7 @@ proc genBreakState(p: BProc, n: PNode) = if n.sons[0].kind == nkClosure: # XXX this produces quite inefficient code! initLocExpr(p, n.sons[0].sons[1], a) - lineF(p, cpsStmts, "if (($1->Field0) < 0) break;$n", [rdLoc(a)]) + lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)]) else: initLocExpr(p, n.sons[0], a) # the environment is guaranteed to contain the 'state' field at offset 0: diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6da156ba6..440468ac4 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -121,14 +121,14 @@ type capturedVars: seq[PSym] # captured variables in this environment deps: seq[TDep] # dependencies up: PEnv - tup: PType + obj: PType - TInnerContext {.final.} = object + TInnerContext = object fn: PSym closureParam: PSym localsToAccess: TIdNodeTable - TOuterContext {.final.} = object + TOuterContext = object fn: PSym # may also be a module! currentEnv: PEnv isIter: bool # first class iterator? @@ -139,8 +139,13 @@ type up: POuterContext closureParam, state, resultSym: PSym # only if isIter - tup: PType # only if isIter + obj: PType # only if isIter +proc createObj(owner: PSym, info: TLineInfo): PType = + result = newType(tyObject, owner) + rawAddSon(result, nil) + incl result.flags, tfFinal + result.n = newNodeI(nkRecList, info) proc getStateType(iter: PSym): PType = var n = newNodeI(nkRange, iter.info) @@ -185,13 +190,14 @@ proc getEnvParam(routine: PSym): PSym = if hidden.kind == nkSym and hidden.sym.name.s == paramName: result = hidden.sym -proc addField(tup: PType, s: PSym) = - var field = newSym(skField, s.name, s.owner, s.info) +proc addField(obj: PType; s: PSym) = + # because of 'gensym' support, we have to mangle the name with its ID. + # This is hacky but the clean solution is much more complex than it looks. + var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info) let t = skipIntLit(s.typ) field.typ = t - field.position = sonsLen(tup) - addSon(tup.n, newSymNode(field)) - rawAddSon(tup, t) + field.position = sonsLen(obj.n) + addSon(obj.n, newSymNode(field)) proc initIterContext(c: POuterContext, iter: PSym) = c.fn = iter @@ -199,25 +205,24 @@ proc initIterContext(c: POuterContext, iter: PSym) = var cp = getEnvParam(iter) if cp == nil: - c.tup = newType(tyTuple, iter) - c.tup.n = newNodeI(nkRecList, iter.info) + c.obj = createObj(iter, iter.info) cp = newSym(skParam, getIdent(paramName), iter, iter.info) incl(cp.flags, sfFromGeneric) cp.typ = newType(tyRef, iter) - rawAddSon(cp.typ, c.tup) + rawAddSon(cp.typ, c.obj) addHiddenParam(iter, cp) c.state = createStateField(iter) - addField(c.tup, c.state) + addField(c.obj, c.state) else: - c.tup = cp.typ.sons[0] - assert c.tup.kind == tyTuple - if c.tup.len > 0: - c.state = c.tup.n[0].sym + c.obj = cp.typ.sons[0] + assert c.obj.kind == tyObject + if c.obj.n.len > 0: + c.state = c.obj.n[0].sym else: c.state = createStateField(iter) - addField(c.tup, c.state) + addField(c.obj, c.state) c.closureParam = cp if iter.typ.sons[0] != nil: @@ -244,8 +249,7 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv = new(result) result.deps = @[] result.capturedVars = @[] - result.tup = newType(tyTuple, outerProc) - result.tup.n = newNodeI(nkRecList, outerProc.info) + result.obj = createObj(outerProc, outerProc.info) result.up = up result.attachedNode = n @@ -254,28 +258,28 @@ proc addCapturedVar(e: PEnv, v: PSym) = if x == v: return # XXX meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - if e.tup.len == 0: addField(e.tup, createStateField(v.owner)) + if e.obj.n.len == 0: addField(e.obj, createStateField(v.owner)) e.capturedVars.add(v) - addField(e.tup, v) + addField(e.obj, v) proc addDep(e, d: PEnv, owner: PSym): PSym = for x, field in items(e.deps): if x == d: return field - var pos = sonsLen(e.tup) + var pos = sonsLen(e.obj.n) result = newSym(skField, getIdent(upName & $pos), owner, owner.info) result.typ = newType(tyRef, owner) result.position = pos - assert d.tup != nil - rawAddSon(result.typ, d.tup) - addField(e.tup, result) + assert d.obj != nil + rawAddSon(result.typ, d.obj) + addField(e.obj, result) e.deps.add((d, result)) proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode = # returns a[].b as a node var deref = newNodeI(nkHiddenDeref, info) deref.typ = a.typ.sons[0] - assert deref.typ.kind == tyTuple - let field = getSymFromList(deref.typ.n, b.name) + assert deref.typ.kind == tyObject + let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id)) assert field != nil, b.name.s addSon(deref, a) result = newNodeI(nkDotExpr, info) @@ -302,11 +306,11 @@ proc addClosureParam(i: PInnerContext, e: PEnv) = cp = newSym(skParam, getIdent(paramName), i.fn, i.fn.info) incl(cp.flags, sfFromGeneric) cp.typ = newType(tyRef, i.fn) - rawAddSon(cp.typ, e.tup) + rawAddSon(cp.typ, e.obj) addHiddenParam(i.fn, cp) else: - e.tup = cp.typ.sons[0] - assert e.tup.kind == tyTuple + e.obj = cp.typ.sons[0] + assert e.obj.kind == tyObject i.closureParam = cp #echo "closure param added for ", i.fn.name.s, " ", i.fn.id @@ -357,7 +361,7 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym, access = indirectAccess(access, addDep(e, it, i.fn), info) access = indirectAccess(access, local, info) if o.isIter: - if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) + if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local) else: incl(o.capturedVars, local.id) idNodeTablePut(i.localsToAccess, local, access) @@ -543,7 +547,7 @@ proc newClosureCreationVar(o: POuterContext; e: PEnv): PSym = result = newSym(skVar, getIdent(envName), o.fn, e.attachedNode.info) incl(result.flags, sfShadowed) result.typ = newType(tyRef, o.fn) - result.typ.rawAddSon(e.tup) + result.typ.rawAddSon(e.obj) proc getClosureVar(o: POuterContext; e: PEnv): PSym = if e.createdVar == nil: @@ -669,7 +673,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode = var local = n.sym if o.isIter and interestingIterVar(local) and o.fn.id == local.owner.id: - if not containsOrIncl(o.capturedVars, local.id): addField(o.tup, local) + if not containsOrIncl(o.capturedVars, local.id): addField(o.obj, local) return indirectAccess(newSymNode(o.closureParam), local, n.info) var closure = PEnv(idTableGet(o.lambdasToEnv, local))