Merge branch 'devel' of https://www.github.com/Araq/Nimrod into devel

This commit is contained in:
Zahary Karadjov 2014-01-26 01:38:45 +02:00
commit 5d712e0d3f
45 changed files with 668 additions and 271 deletions

View file

@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: PRope): PRope =
result = if r == nil: r else: con(r, ~", ")
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope
@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ~", ")
template genCallPattern {.dirty.} =
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~", ")
@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
genAssignment(p, d, list, {}) # no need for deep copying
else:
genCallPattern()

View file

@ -116,9 +116,9 @@ type
TDep = tuple[e: PEnv, field: PSym]
TEnv {.final.} = object of TObject
attachedNode: PNode
closure: PSym # if != nil it is a used environment
createdVar: PSym # if != nil it is a used environment
capturedVars: seq[PSym] # captured variables in this environment
deps: seq[TDep] # dependencies
deps: seq[TDep] # dependencies
up: PEnv
tup: PType
@ -130,12 +130,99 @@ type
TOuterContext {.final.} = object
fn: PSym # may also be a module!
currentEnv: PEnv
isIter: bool # first class iterator?
capturedVars, processed: TIntSet
localsToEnv: TIdTable # PSym->PEnv mapping
localsToAccess: TIdNodeTable
lambdasToEnv: TIdTable # PSym->PEnv mapping
up: POuterContext
closureParam, state, resultSym: PSym # only if isIter
tup: PType # only if isIter
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc createStateField(iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = getStateType(iter)
proc newIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
#echo "produced environment: ", param.id, " for ", routine.name.s
proc getHiddenParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
assert hidden.kind == nkSym
result = hidden.sym
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
proc addField(tup: PType, s: PSym) =
var field = newSym(skField, s.name, s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(tup)
addSon(tup.n, newSymNode(field))
rawAddSon(tup, t)
proc initIterContext(c: POuterContext, iter: PSym) =
c.fn = iter
c.capturedVars = initIntSet()
var cp = getEnvParam(iter)
if cp == nil:
c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info)
cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup)
addHiddenParam(iter, cp)
c.state = createStateField(iter)
addField(c.tup, 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
else:
c.state = createStateField(iter)
addField(c.tup, c.state)
c.closureParam = cp
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
#iter.ast.add(newSymNode(c.resultSym))
proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
new(result)
result.fn = fn
@ -144,12 +231,14 @@ proc newOuterContext(fn: PSym, up: POuterContext = nil): POuterContext =
initIdNodeTable(result.localsToAccess)
initIdTable(result.localsToEnv)
initIdTable(result.lambdasToEnv)
result.isIter = fn.kind == skIterator and fn.typ.callConv == ccClosure
if result.isIter: initIterContext(result, fn)
proc newInnerContext(fn: PSym): PInnerContext =
new(result)
result.fn = fn
initIdNodeTable(result.localsToAccess)
proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
new(result)
result.deps = @[]
@ -159,17 +248,12 @@ proc newEnv(outerProc: PSym, up: PEnv, n: PNode): PEnv =
result.up = up
result.attachedNode = n
proc addField(tup: PType, s: PSym) =
var field = newSym(skField, s.name, s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(tup)
addSon(tup.n, newSymNode(field))
rawAddSon(tup, t)
proc addCapturedVar(e: PEnv, v: PSym) =
for x in e.capturedVars:
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))
e.capturedVars.add(v)
addField(e.tup, v)
@ -189,6 +273,7 @@ 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 field != nil, b.name.s
addSon(deref, a)
@ -205,33 +290,24 @@ proc newCall(a, b: PSym): PNode =
result.add newSymNode(a)
result.add newSymNode(b)
proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos]
# -1 is correct here as param.position is 0 based but we have at position 0
# some nkEffect node:
param.position = params.len-1
addSon(params, newSymNode(param))
incl(routine.typ.flags, tfCapturesEnv)
#echo "produced environment: ", param.id, " for ", routine.name.s
proc getHiddenParam(routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
assert hidden.kind == nkSym
result = hidden.sym
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
result = s.kind in {skProc, skMethod, skConverter} and
result = (s.kind in {skProc, skMethod, skConverter} or
s.kind == skIterator and s.typ.callConv == ccClosure) and
s.skipGenericOwner == outerProc
#s.typ.callConv == ccClosure
proc addClosureParam(i: PInnerContext, e: PEnv) =
var 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)
var cp = getEnvParam(i.fn)
if cp == nil:
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)
addHiddenParam(i.fn, cp)
else:
e.tup = cp.typ.sons[0]
assert e.tup.kind == tyTuple
i.closureParam = cp
addHiddenParam(i.fn, i.closureParam)
#echo "closure param added for ", i.fn.name.s, " ", i.fn.id
proc dummyClosureParam(o: POuterContext, i: PInnerContext) =
@ -306,7 +382,9 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
var s = n.sym
if interestingVar(s) and i.fn.id != s.owner.id:
captureVar(o, i, s, n.info)
elif isInnerProc(s, o.fn) and tfCapturesEnv in s.typ.flags and s != i.fn:
elif s.kind in {skProc, skMethod, skConverter} and
s.skipGenericOwner == o.fn and
tfCapturesEnv in s.typ.flags and s != i.fn:
# call to some other inner proc; we need to track the dependencies for
# this:
let env = PEnv(idTableGet(o.lambdasToEnv, i.fn))
@ -314,7 +392,7 @@ proc gatherVars(o: POuterContext, i: PInnerContext, n: PNode) =
if o.currentEnv != env:
discard addDep(o.currentEnv, env, i.fn)
internalError(n.info, "too complex environment handling required")
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure: discard
else:
for k in countup(0, sonsLen(n) - 1):
gatherVars(o, i, n.sons[k])
@ -366,10 +444,11 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode =
else:
# captured symbol?
result = idNodeTableGet(i.localsToAccess, n.sym)
of nkLambdaKinds:
result = transformInnerProc(o, i, n.sons[namePos])
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformInnerProc(o, i, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure:
# don't recurse here:
discard
else:
@ -400,8 +479,9 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
if inner.closureParam != nil:
let ti = transformInnerProc(o, inner, body)
if ti != nil: n.sym.ast.sons[bodyPos] = ti
of nkLambdaKinds:
searchForInnerProcs(o, n.sons[namePos])
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
searchForInnerProcs(o, n.sons[namePos])
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
# some nodes open a new scope, so they are candidates for the insertion
# of closure creation; however for simplicity we merge closures between
@ -438,7 +518,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) =
else:
internalError(it.info, "transformOuter")
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
nkClosure:
# don't recurse here:
# XXX recurse here and setup 'up' pointers
discard
@ -463,19 +543,20 @@ proc addVar*(father, v: PNode) =
addSon(vpart, ast.emptyNode)
addSon(father, vpart)
proc getClosureVar(o: POuterContext, e: PEnv): PSym =
if e.closure == nil:
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)
e.closure = result
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)
proc getClosureVar(o: POuterContext; e: PEnv): PSym =
if e.createdVar == nil:
result = newClosureCreationVar(o, e)
e.createdVar = result
else:
result = e.closure
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = e.createdVar
proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PSym): PNode =
result = newNodeI(nkStmtList, env.info)
var v = newNodeI(nkVarSection, env.info)
addVar(v, newSymNode(env))
@ -496,6 +577,65 @@ proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
# add ``env.up = env2``
result.add(newAsgnStmt(indirectAccess(env, field, env.info),
newSymNode(getClosureVar(o, e)), env.info))
proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
var env = getClosureVar(o, scope)
result = rawClosureCreation(o, scope, env)
proc generateIterClosureCreation(o: POuterContext; env: PEnv;
scope: PNode): PSym =
result = newClosureCreationVar(o, env)
let cc = rawClosureCreation(o, env, result)
var insertPoint = scope.sons[0]
if insertPoint.kind == nkEmpty: scope.sons[0] = cc
else:
assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
for x in cc: insertPoint.add(x)
if env.createdVar == nil: env.createdVar = result
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transformOuterProc(o: POuterContext, n: PNode): PNode
proc transformYield(c: POuterContext, n: PNode): PNode =
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transformOuterProc(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
proc transformReturn(c: POuterContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
proc outerProcSons(o: POuterContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if n == nil: return nil
@ -503,10 +643,25 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkSym:
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)
return indirectAccess(newSymNode(o.closureParam), local, n.info)
var closure = PEnv(idTableGet(o.lambdasToEnv, local))
if closure != nil:
# we need to replace the lambda with '(lambda, env)':
let a = closure.closure
# we need to replace the lambda with '(lambda, env)':
if local.kind == skIterator and local.typ.callConv == ccClosure:
# consider: [i1, i2, i1] Since we merged the iterator's closure
# with the captured owning variables, we need to generate the
# closure generation code again:
#if local == o.fn: message(n.info, errRecursiveDependencyX, local.name.s)
# XXX why doesn't this work?
let createdVar = generateIterClosureCreation(o, closure,
closure.attachedNode)
return makeClosure(local, createdVar, n.info)
let a = closure.createdVar
if a != nil:
return makeClosure(local, a, n.info)
else:
@ -516,7 +671,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
if scope.sons[0].kind == nkEmpty:
# change the empty node to contain the closure construction:
scope.sons[0] = generateClosureCreation(o, closure)
let x = closure.closure
let x = closure.createdVar
assert x != nil
return makeClosure(local, x, n.info)
@ -535,20 +690,47 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
assert result != nil, "cannot find: " & local.name.s
# else it is captured by copy and this means that 'outer' should continue
# to access the local as a local.
of nkLambdaKinds:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef:
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
result = transformOuterProc(o, n.sons[namePos])
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkClosure:
# don't recurse here:
discard
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
let x = transformOuterProc(o, n.sons[1])
if x != nil: n.sons[1] = x
result = transformOuterConv(n)
of nkYieldStmt:
if o.isIter: result = transformYield(o, n)
else: outerProcSons(o, n)
of nkReturnStmt:
if o.isIter: result = transformReturn(o, n)
else: outerProcSons(o, n)
else:
for i in countup(0, sonsLen(n) - 1):
let x = transformOuterProc(o, n.sons[i])
if x != nil: n.sons[i] = x
outerProcSons(o, n)
proc liftIterator(c: POuterContext, body: PNode): PNode =
let iter = c.fn
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transformOuterProc(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftLambdas*(fn: PSym, body: PNode): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
@ -572,8 +754,11 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
idTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
searchForInnerProcs(o, body)
discard transformOuterProc(o, body)
result = ex
if o.isIter:
result = liftIterator(o, ex)
else:
discard transformOuterProc(o, body)
result = ex
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
@ -588,140 +773,15 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
# ------------------- iterator transformation --------------------------------
discard """
iterator chain[S, T](a, b: *S->T, args: *S): T =
for x in a(args): yield x
for x in b(args): yield x
let c = chain(f, g)
for x in c: echo x
# translated to:
let c = chain( (f, newClosure(f)), (g, newClosure(g)), newClosure(chain))
"""
type
TIterContext {.final, pure.} = object
iter, closureParam, state, resultSym: PSym
capturedVars: TIntSet
tup: PType
proc newIterResult(iter: PSym): PSym =
result = iter.ast.sons[resultPos].sym
when false:
result = newSym(skResult, getIdent":result", iter, iter.info)
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
proc interestingIterVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
proc transfIterBody(c: var TIterContext, n: PNode): PNode =
# gather used vars for closure generation
if n == nil: return nil
case n.kind
of nkSym:
var s = n.sym
if interestingIterVar(s) and c.iter.id == s.owner.id:
if not containsOrIncl(c.capturedVars, s.id): addField(c.tup, s)
result = indirectAccess(newSymNode(c.closureParam), s, n.info)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
of nkYieldStmt:
inc c.state.typ.n.sons[1].intVal
let stateNo = c.state.typ.n.sons[1].intVal
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
var a = newNodeI(nkAsgn, n.sons[0].info)
var retVal = transfIterBody(c, n.sons[0])
addSon(a, newSymNode(c.resultSym))
addSon(a, if retVal.isNil: n.sons[0] else: retVal)
retStmt.add(a)
else:
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
result.add(retStmt)
result.add(stateLabelStmt)
of nkReturnStmt:
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),c.state,n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
result.add(n)
else:
for i in countup(0, sonsLen(n)-1):
let x = transfIterBody(c, n.sons[i])
if x != nil: n.sons[i] = x
proc getStateType(iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
rawAddSon(result, getSysType(tyInt))
proc liftIterator*(iter: PSym, body: PNode): PNode =
var c: TIterContext
c.iter = iter
c.capturedVars = initIntSet()
c.tup = newType(tyTuple, iter)
c.tup.n = newNodeI(nkRecList, iter.info)
var cp = newSym(skParam, getIdent(paramName), iter, iter.info)
incl(cp.flags, sfFromGeneric)
cp.typ = newType(tyRef, iter)
rawAddSon(cp.typ, c.tup)
c.closureParam = cp
addHiddenParam(iter, cp)
c.state = newSym(skField, getIdent(":state"), iter, iter.info)
c.state.typ = getStateType(iter)
addField(c.tup, c.state)
if iter.typ.sons[0] != nil:
c.resultSym = newIterResult(iter)
iter.ast.add(newSymNode(c.resultSym))
result = newNodeI(nkStmtList, iter.info)
var gs = newNodeI(nkGotoState, iter.info)
gs.add(indirectAccess(newSymNode(c.closureParam), c.state, iter.info))
result.add(gs)
var state0 = newNodeI(nkState, iter.info)
state0.add(newIntNode(nkIntLit, 0))
result.add(state0)
let newBody = transfIterBody(c, body)
if newBody != nil:
result.add(newBody)
else:
result.add(body)
var stateAsgnStmt = newNodeI(nkAsgn, iter.info)
stateAsgnStmt.add(indirectAccess(newSymNode(c.closureParam),
c.state,iter.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
result.add(stateAsgnStmt)
proc liftIterSym*(n: PNode): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let iter = n.sym
assert iter.kind == skIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var env = copySym(getHiddenParam(iter))
env.kind = skLet
var v = newNodeI(nkVarSection, n.info)
addVar(v, newSymNode(env))
result.add(v)
@ -766,7 +826,7 @@ proc liftForLoop*(body: PNode): PNode =
# static binding?
var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skIterator:
# createClose()
# createClosure()
let iter = call[0].sym
assert iter.kind == skIterator
env = copySym(getHiddenParam(iter))

View file

@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.

View file

@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -31,7 +31,7 @@ type
TParser*{.final.} = object # a TParser object represents a module that
# is being parsed
currInd: int # current indentation
firstTok: bool
firstTok, strongSpaces: bool
lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token
inPragma: int
@ -1048,6 +1048,7 @@ proc parseTypeDesc(p: var TParser): PNode =
proc parseTypeDefAux(p: var TParser): PNode =
#| typeDefAux = simpleExpr
#| | 'generic' typeClass
result = simpleExpr(p, pmTypeDef)
proc makeCall(n: PNode): PNode =
@ -1208,8 +1209,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
if p.tok.tokType == tkComment:
skipComment(p, result)
addSon(result, ast.emptyNode)
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or
p.tok.tokType == tkEof:
elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
# NL terminates:
addSon(result, ast.emptyNode)
else:
@ -1672,6 +1672,9 @@ proc parseTypeClassParam(p: var TParser): PNode =
result = p.parseSymbol
proc parseTypeClass(p: var TParser): PNode =
#| typeClassParam = ('var')? symbol
#| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
#| &IND{>} stmt
result = newNodeP(nkTypeClassTy, p)
getTok(p)
var args = newNode(nkArgList)

View file

@ -426,6 +426,8 @@ proc lsub(n: PNode): int =
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
of nkDistinctTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) +
len("Distinct")
of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
len("static[]")
of nkTypeDef: result = lsons(n) + 3
of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
of nkProcTy: result = lsons(n) + len("proc_")
@ -701,6 +703,19 @@ proc gproc(g: var TSrcGen, n: PNode) =
gcoms(g)
dedent(g)
proc gTypeClassTy(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
putWithSpace(g, tkGeneric, "generic")
gsons(g, n[0], c) # arglist
gsub(g, n[1]) # pragmas
gsub(g, n[2]) # of
gcoms(g)
indentNL(g)
gcoms(g)
gstmts(g, n[3], c)
dedent(g)
proc gblock(g: var TSrcGen, n: PNode) =
var c: TContext
initContext(c)
@ -1054,6 +1069,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0])
else:
put(g, tkShared, "shared")
of nkStaticTy:
put(g, tkStatic, "static")
put(g, tkBracketLe, "[")
if n.len > 0:
gsub(g, n.sons[0])
put(g, tkBracketRi, "]")
of nkEnumTy:
if sonsLen(n) > 0:
putWithSpace(g, tkEnum, "enum")
@ -1251,6 +1272,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(META|")
gsub(g, n.sons[0])
put(g, tkParRi, ")")
of nkGotoState, nkState:
var c: TContext
initContext c
putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
gsons(g, n, c)
of nkTypeClassTy:
gTypeClassTy(g, n)
else:
#nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')

View file

@ -116,7 +116,10 @@ proc generateDestructor(c: PContext, t: PType): PNode =
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
if stmt != nil: addLine(stmt)
else:
internalAssert false
# XXX just skip it for now so that the compiler doesn't crash, but
# please zahary fix it! arbitrary nesting of nkRecList/nkRecCase is
# possible. Any thread example seems to trigger this.
discard
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors

View file

@ -868,6 +868,8 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
return semStmt(c, x)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda
result = semProcAnnotation(c, n)
if result != nil: return result
result = n
@ -949,11 +951,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
checkSonsLen(n, bodyPos + 1)
var s: PSym
var typeIsDetermined = false
var isAnon = false
if n[namePos].kind != nkSym:
assert phase == stepRegisterSymbol
if n[namePos].kind == nkEmpty:
s = newSym(kind, idAnon, getCurrOwner(), n.info)
isAnon = true
else:
s = semIdentDef(c, n.sons[0], kind)
n.sons[namePos] = newSymNode(s)
@ -996,11 +1000,13 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
rawAddSon(s.typ, nil)
if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
if s.kind == skIterator: s.typ.flags.incl(tfIterator)
if s.kind == skIterator:
s.typ.flags.incl(tfIterator)
var proto = searchForProc(c, s.scope, s)
if proto == nil:
s.typ.callConv = lastOptionEntry(c).defaultCC
if s.kind == skIterator and isAnon: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC
# add it here, so that recursive procs are possible:
if sfGenSym in s.flags: discard
elif kind in OverloadableSyms:
@ -1078,6 +1084,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner()
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
if isAnon: result.typ = s.typ
proc determineType(c: PContext, s: PSym) =
if s.typ != nil: return

View file

@ -116,8 +116,8 @@ proc hasGenericArguments*(n: PNode): bool =
(n.sym.kind == skType and
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
else:
for s in n.sons:
if hasGenericArguments(s): return true
for i in 0.. <n.safeLen:
if hasGenericArguments(n.sons[i]): return true
return false
proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =

View file

@ -113,8 +113,8 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
result[1] = ri
proc transformSymAux(c: PTransf, n: PNode): PNode =
if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
return liftIterSym(n)
#if n.sym.kind == skIterator and n.sym.typ.callConv == ccClosure:
# return liftIterSym(n)
var b: PNode
var tc = c.transCon
if sfBorrow in n.sym.flags:
@ -636,6 +636,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
s.ast.sons[bodyPos] = n.sons[bodyPos]
#n.sons[bodyPos] = liftLambdas(s, n)
#if n.kind == nkMethodDef: methodDef(s, false)
#if n.kind == nkIteratorDef and n.typ != nil:
# return liftIterSym(n.sons[namePos]).PTransNode
result = PTransNode(n)
of nkMacroDef:
# XXX no proper closure support yet:
@ -708,6 +710,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
# XXX comment handling really sucks:
if importantComments():
PNode(result).comment = n.comment
of nkClosure: return PTransNode(n)
else:
result = transformSons(c, n)
var cnst = getConstExpr(c.module, PNode(result))
@ -738,8 +741,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
var c = openTransf(module, "")
result = processTransf(c, n, prc)
result = liftLambdas(prc, result)
if prc.kind == skIterator and prc.typ.callConv == ccClosure:
result = lambdalifting.liftIterator(prc, result)
#if prc.kind == skIterator and prc.typ.callConv == ccClosure:
# result = lambdalifting.liftIterator(prc, result)
incl(result.flags, nfTransf)
when useEffectSystem: trackProc(prc, result)

View file

@ -1057,6 +1057,7 @@ proc fixType(result, n: PNode) {.inline.} =
# XXX do it deeply for complex values; there seems to be no simple
# solution except to check it deeply here.
#if result.typ.isNil: result.typ = n.typ
discard
proc execute(c: PCtx, start: int): PNode =
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
@ -1118,6 +1119,7 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
var c = globalCtx
c.mode = mode
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
if c.code[start].opcode == opcEof: return emptyNode
assert c.code[start].opcode != opcEof
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
newSeq(tos.slots, c.prc.maxSlots)