mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
lambda lifting support for iterToProc plugin
This commit is contained in:
@@ -126,6 +126,7 @@ type
|
||||
fn, closureParam, state, resultSym: PSym # most are only valid if
|
||||
# fn.kind == skClosureIterator
|
||||
obj: PType
|
||||
isIterator: bool
|
||||
|
||||
PEnv = ref TEnv
|
||||
TEnv {.final.} = object of RootObj
|
||||
@@ -197,24 +198,29 @@ proc getHiddenParam(routine: PSym): PSym =
|
||||
result = hidden.sym
|
||||
assert sfFromGeneric in result.flags
|
||||
|
||||
proc getEnvParam(routine: PSym): PSym =
|
||||
proc getEnvParam*(routine: PSym): PSym =
|
||||
let params = routine.ast.sons[paramsPos]
|
||||
let hidden = lastSon(params)
|
||||
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
|
||||
result = hidden.sym
|
||||
assert sfFromGeneric in result.flags
|
||||
|
||||
proc initIter(iter: PSym): TIter =
|
||||
proc initIter(iter: PSym; ptrType: PType = nil): TIter =
|
||||
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)
|
||||
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)
|
||||
incl(cp.flags, sfFromGeneric)
|
||||
cp.typ = newType(tyRef, iter)
|
||||
rawAddSon(cp.typ, result.obj)
|
||||
if ptrType != nil:
|
||||
cp.typ = ptrType
|
||||
else:
|
||||
cp.typ = newType(tyRef, iter)
|
||||
rawAddSon(cp.typ, result.obj)
|
||||
addHiddenParam(iter, cp)
|
||||
else:
|
||||
result.obj = cp.typ.sons[0]
|
||||
@@ -534,6 +540,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
let fn = n.sym
|
||||
if isInnerProc(fn, o.fn) and not containsOrIncl(o.processed, fn.id):
|
||||
let body = fn.getBody
|
||||
if nfLL in body.flags: return
|
||||
|
||||
# handle deeply nested captures:
|
||||
let ex = closureCreationPoint(body)
|
||||
@@ -794,7 +801,7 @@ proc finishEnvironments(o: POuterContext) =
|
||||
proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
if nfLL in n.flags:
|
||||
result = nil
|
||||
elif it.fn.kind == skClosureIterator:
|
||||
elif it.isIterator:
|
||||
# unfortunately control flow is still convoluted and we can end up
|
||||
# multiple times here for the very same iterator. We shield against this
|
||||
# with some rather primitive check for now:
|
||||
@@ -843,7 +850,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
if newBody != nil:
|
||||
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:
|
||||
# every local goes through the closure:
|
||||
#if not containsOrIncl(o.capturedVars, local.id):
|
||||
@@ -931,7 +938,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
when false:
|
||||
if n.sons[1].kind == nkSym:
|
||||
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:
|
||||
# every local goes through the closure:
|
||||
addUniqueField(it.obj, local)
|
||||
@@ -941,14 +948,25 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
|
||||
if x != nil: n.sons[1] = x
|
||||
result = transformOuterConv(n)
|
||||
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)
|
||||
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)
|
||||
|
||||
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 =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# 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:
|
||||
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:
|
||||
markUsed(info, paramType.sym)
|
||||
styleCheckUse(info, paramType.sym)
|
||||
@@ -1002,7 +997,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
# see tchainediterators
|
||||
# in cases like iterator foo(it: iterator): type(it)
|
||||
# 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.n.typ = r
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ when defined(emscripten):
|
||||
MAP_PRIVATE = 2'i32 # Changes are private
|
||||
|
||||
var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
|
||||
type
|
||||
type
|
||||
PEmscriptenMMapBlock = ptr EmscriptenMMapBlock
|
||||
EmscriptenMMapBlock {.pure, inheritable.} = object
|
||||
realSize: int # size of previous chunk; for coalescing
|
||||
@@ -399,6 +399,9 @@ iterator allObjects(m: MemRegion): pointer {.inline.} =
|
||||
let c = cast[PBigChunk](c)
|
||||
yield addr(c.data)
|
||||
|
||||
proc iterToProc*(iter: typed, envType: typedesc; procName: untyped) {.
|
||||
magic: "Plugin", compileTime.}
|
||||
|
||||
proc isCell(p: pointer): bool {.inline.} =
|
||||
result = cast[ptr FreeCell](p).zeroField >% 1
|
||||
|
||||
|
||||
@@ -6,8 +6,11 @@ discard """
|
||||
8
|
||||
12
|
||||
'''
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
# Will eventually fix it...
|
||||
|
||||
iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
|
||||
for e in s: yield f(e)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user