diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index cccc94756..be1631af0 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -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 ... diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim new file mode 100644 index 000000000..91e1d2783 --- /dev/null +++ b/compiler/plugins/itersgen.nim @@ -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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index bb59a9e75..683b6455f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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 diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 3ebbc8c1e..b4462ed83 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -40,7 +40,7 @@ when defined(emscripten): MAP_PRIVATE = 2'i32 # Changes are private var MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "".}: 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 diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim index 3ec79f68d..fc1a8f934 100644 --- a/tests/iter/titerable.nim +++ b/tests/iter/titerable.nim @@ -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)