lambda lifting support for iterToProc plugin
This commit is contained in:
parent
d7433d02bc
commit
217e0ab6e9
5 changed files with 88 additions and 18 deletions
|
|
@ -126,6 +126,7 @@ type
|
||||||
fn, closureParam, state, resultSym: PSym # most are only valid if
|
fn, closureParam, state, resultSym: PSym # most are only valid if
|
||||||
# fn.kind == skClosureIterator
|
# fn.kind == skClosureIterator
|
||||||
obj: PType
|
obj: PType
|
||||||
|
isIterator: bool
|
||||||
|
|
||||||
PEnv = ref TEnv
|
PEnv = ref TEnv
|
||||||
TEnv {.final.} = object of RootObj
|
TEnv {.final.} = object of RootObj
|
||||||
|
|
@ -197,24 +198,29 @@ proc getHiddenParam(routine: PSym): PSym =
|
||||||
result = hidden.sym
|
result = hidden.sym
|
||||||
assert sfFromGeneric in result.flags
|
assert sfFromGeneric in result.flags
|
||||||
|
|
||||||
proc getEnvParam(routine: PSym): PSym =
|
proc getEnvParam*(routine: PSym): PSym =
|
||||||
let params = routine.ast.sons[paramsPos]
|
let params = routine.ast.sons[paramsPos]
|
||||||
let hidden = lastSon(params)
|
let hidden = lastSon(params)
|
||||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||||
result = hidden.sym
|
result = hidden.sym
|
||||||
assert sfFromGeneric in result.flags
|
assert sfFromGeneric in result.flags
|
||||||
|
|
||||||
proc initIter(iter: PSym): TIter =
|
proc initIter(iter: PSym; ptrType: PType = nil): TIter =
|
||||||
result.fn = iter
|
result.fn = iter
|
||||||
if iter.kind == skClosureIterator:
|
result.isIterator = ptrType != nil or iter.kind == skClosureIterator
|
||||||
|
#echo "fuck you ", ptrType != nil
|
||||||
|
if result.isIterator:
|
||||||
var cp = getEnvParam(iter)
|
var cp = getEnvParam(iter)
|
||||||
if cp == nil:
|
if cp == nil:
|
||||||
result.obj = createEnvObj(iter)
|
result.obj = if ptrType != nil: ptrType.lastSon else: createEnvObj(iter)
|
||||||
|
|
||||||
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
|
||||||
incl(cp.flags, sfFromGeneric)
|
incl(cp.flags, sfFromGeneric)
|
||||||
cp.typ = newType(tyRef, iter)
|
if ptrType != nil:
|
||||||
rawAddSon(cp.typ, result.obj)
|
cp.typ = ptrType
|
||||||
|
else:
|
||||||
|
cp.typ = newType(tyRef, iter)
|
||||||
|
rawAddSon(cp.typ, result.obj)
|
||||||
addHiddenParam(iter, cp)
|
addHiddenParam(iter, cp)
|
||||||
else:
|
else:
|
||||||
result.obj = cp.typ.sons[0]
|
result.obj = cp.typ.sons[0]
|
||||||
|
|
@ -534,6 +540,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||||
let fn = n.sym
|
let fn = n.sym
|
||||||
if isInnerProc(fn, o.fn) and not containsOrIncl(o.processed, fn.id):
|
if isInnerProc(fn, o.fn) and not containsOrIncl(o.processed, fn.id):
|
||||||
let body = fn.getBody
|
let body = fn.getBody
|
||||||
|
if nfLL in body.flags: return
|
||||||
|
|
||||||
# handle deeply nested captures:
|
# handle deeply nested captures:
|
||||||
let ex = closureCreationPoint(body)
|
let ex = closureCreationPoint(body)
|
||||||
|
|
@ -794,7 +801,7 @@ proc finishEnvironments(o: POuterContext) =
|
||||||
proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
|
proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||||
if nfLL in n.flags:
|
if nfLL in n.flags:
|
||||||
result = nil
|
result = nil
|
||||||
elif it.fn.kind == skClosureIterator:
|
elif it.isIterator:
|
||||||
# unfortunately control flow is still convoluted and we can end up
|
# unfortunately control flow is still convoluted and we can end up
|
||||||
# multiple times here for the very same iterator. We shield against this
|
# multiple times here for the very same iterator. We shield against this
|
||||||
# with some rather primitive check for now:
|
# with some rather primitive check for now:
|
||||||
|
|
@ -843,7 +850,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||||
if newBody != nil:
|
if newBody != nil:
|
||||||
local.ast.sons[bodyPos] = newBody
|
local.ast.sons[bodyPos] = newBody
|
||||||
|
|
||||||
if it.fn.kind == skClosureIterator and interestingIterVar(local) and
|
if it.isIterator and interestingIterVar(local) and
|
||||||
it.fn == local.owner:
|
it.fn == local.owner:
|
||||||
# every local goes through the closure:
|
# every local goes through the closure:
|
||||||
#if not containsOrIncl(o.capturedVars, local.id):
|
#if not containsOrIncl(o.capturedVars, local.id):
|
||||||
|
|
@ -931,7 +938,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||||
when false:
|
when false:
|
||||||
if n.sons[1].kind == nkSym:
|
if n.sons[1].kind == nkSym:
|
||||||
var local = n.sons[1].sym
|
var local = n.sons[1].sym
|
||||||
if it.fn.kind == skClosureIterator and interestingIterVar(local) and
|
if it.isIterator and interestingIterVar(local) and
|
||||||
it.fn == local.owner:
|
it.fn == local.owner:
|
||||||
# every local goes through the closure:
|
# every local goes through the closure:
|
||||||
addUniqueField(it.obj, local)
|
addUniqueField(it.obj, local)
|
||||||
|
|
@ -941,14 +948,25 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||||
if x != nil: n.sons[1] = x
|
if x != nil: n.sons[1] = x
|
||||||
result = transformOuterConv(n)
|
result = transformOuterConv(n)
|
||||||
of nkYieldStmt:
|
of nkYieldStmt:
|
||||||
if it.fn.kind == skClosureIterator: result = transformYield(o, n, it)
|
if it.isIterator: result = transformYield(o, n, it)
|
||||||
else: outerProcSons(o, n, it)
|
else: outerProcSons(o, n, it)
|
||||||
of nkReturnStmt:
|
of nkReturnStmt:
|
||||||
if it.fn.kind == skClosureIterator: result = transformReturn(o, n, it)
|
if it.isIterator: result = transformReturn(o, n, it)
|
||||||
else: outerProcSons(o, n, it)
|
else: outerProcSons(o, n, it)
|
||||||
else:
|
else:
|
||||||
outerProcSons(o, n, it)
|
outerProcSons(o, n, it)
|
||||||
|
|
||||||
|
proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||||
|
var o = newOuterContext(fn)
|
||||||
|
let ex = closureCreationPoint(body)
|
||||||
|
let env = newEnv(o, nil, ex, fn)
|
||||||
|
addParamsToEnv(fn, env)
|
||||||
|
searchForInnerProcs(o, body, env)
|
||||||
|
createEnvironments(o)
|
||||||
|
let it = initIter(fn, ptrType)
|
||||||
|
result = transformOuterProcBody(o, body, it)
|
||||||
|
finishEnvironments(o)
|
||||||
|
|
||||||
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
proc liftLambdas*(fn: PSym, body: PNode): PNode =
|
||||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||||
# the transformation even when compiling to JS ...
|
# the transformation even when compiling to JS ...
|
||||||
|
|
|
||||||
49
compiler/plugins/itersgen.nim
Normal file
49
compiler/plugins/itersgen.nim
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Plugin to transform an inline iterator into a data structure.
|
||||||
|
|
||||||
|
import plugins, ast, astalgo, magicsys, lookups, semdata,
|
||||||
|
lambdalifting, msgs, rodread
|
||||||
|
|
||||||
|
proc iterToProcImpl(c: PContext, n: PNode): PNode =
|
||||||
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
let iter = n[1]
|
||||||
|
if iter.kind != nkSym or iter.sym.kind != skIterator:
|
||||||
|
localError(iter.info, "first argument needs to be an iterator")
|
||||||
|
return
|
||||||
|
if n[2].typ.isNil:
|
||||||
|
localError(n[2].info, "second argument needs to be a type")
|
||||||
|
return
|
||||||
|
if n[3].kind != nkIdent:
|
||||||
|
localError(n[3].info, "third argument needs to be an identifier")
|
||||||
|
return
|
||||||
|
|
||||||
|
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
|
||||||
|
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
|
||||||
|
localError(n[2].info,
|
||||||
|
"type must be a non-generic ref|ptr to object with state field")
|
||||||
|
return
|
||||||
|
let body = liftIterToProc(iter.sym, iter.sym.getBody, t)
|
||||||
|
|
||||||
|
let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
|
||||||
|
prc.typ = copyType(iter.sym.typ, prc, false)
|
||||||
|
excl prc.typ.flags, tfCapturesEnv
|
||||||
|
prc.typ.n.add newSymNode(getEnvParam(iter.sym))
|
||||||
|
prc.typ.rawAddSon t
|
||||||
|
let orig = iter.sym.ast
|
||||||
|
prc.ast = newProcNode(nkProcDef, n.info,
|
||||||
|
name = newSymNode(prc),
|
||||||
|
params = orig[paramsPos],
|
||||||
|
pragmas = orig[pragmasPos],
|
||||||
|
body = body)
|
||||||
|
prc.ast.add iter.sym.ast.sons[resultPos]
|
||||||
|
addInterfaceDecl(c, prc)
|
||||||
|
|
||||||
|
registerPlugin("stdlib", "system", "iterToProc", iterToProcImpl)
|
||||||
|
|
@ -871,11 +871,6 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
||||||
of tyExpr:
|
|
||||||
if procKind notin {skMacro, skTemplate}:
|
|
||||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
|
||||||
#result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
|
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
markUsed(info, paramType.sym)
|
markUsed(info, paramType.sym)
|
||||||
styleCheckUse(info, paramType.sym)
|
styleCheckUse(info, paramType.sym)
|
||||||
|
|
@ -1002,7 +997,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
# see tchainediterators
|
# see tchainediterators
|
||||||
# in cases like iterator foo(it: iterator): type(it)
|
# in cases like iterator foo(it: iterator): type(it)
|
||||||
# we don't need to change the return type to iter[T]
|
# we don't need to change the return type to iter[T]
|
||||||
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
result.flags.incl tfIterator
|
||||||
|
#if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
||||||
|
# XXX Would be nice if we could get rid of this
|
||||||
result.sons[0] = r
|
result.sons[0] = r
|
||||||
result.n.typ = r
|
result.n.typ = r
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,9 @@ iterator allObjects(m: MemRegion): pointer {.inline.} =
|
||||||
let c = cast[PBigChunk](c)
|
let c = cast[PBigChunk](c)
|
||||||
yield addr(c.data)
|
yield addr(c.data)
|
||||||
|
|
||||||
|
proc iterToProc*(iter: typed, envType: typedesc; procName: untyped) {.
|
||||||
|
magic: "Plugin", compileTime.}
|
||||||
|
|
||||||
proc isCell(p: pointer): bool {.inline.} =
|
proc isCell(p: pointer): bool {.inline.} =
|
||||||
result = cast[ptr FreeCell](p).zeroField >% 1
|
result = cast[ptr FreeCell](p).zeroField >% 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ discard """
|
||||||
8
|
8
|
||||||
12
|
12
|
||||||
'''
|
'''
|
||||||
|
disabled: "true"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Will eventually fix it...
|
||||||
|
|
||||||
iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
|
iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
|
||||||
for e in s: yield f(e)
|
for e in s: yield f(e)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue