top level closures should work; transf is not a pass anymore; next steps for first class iterator support
This commit is contained in:
parent
f686647f58
commit
244c14db0b
17 changed files with 293 additions and 229 deletions
|
|
@ -25,7 +25,6 @@ import
|
|||
const
|
||||
genPrefix* = ":tmp" # prefix for generated names
|
||||
|
||||
proc transfPass*(): TPass
|
||||
# implementation
|
||||
|
||||
type
|
||||
|
|
@ -109,54 +108,6 @@ proc transformSons(c: PTransf, n: PNode): PTransNode =
|
|||
for i in countup(0, sonsLen(n)-1):
|
||||
result[i] = transform(c, n.sons[i])
|
||||
|
||||
# Transforming iterators into non-inlined versions is pretty hard, but
|
||||
# unavoidable for not bloating the code too much. If we had direct access to
|
||||
# the program counter, things'd be much easier.
|
||||
# ::
|
||||
#
|
||||
# iterator items(a: string): char =
|
||||
# var i = 0
|
||||
# while i < length(a):
|
||||
# yield a[i]
|
||||
# inc(i)
|
||||
#
|
||||
# for ch in items("hello world"): # `ch` is an iteration variable
|
||||
# echo(ch)
|
||||
#
|
||||
# Should be transformed into::
|
||||
#
|
||||
# type
|
||||
# TItemsClosure = record
|
||||
# i: int
|
||||
# state: int
|
||||
# proc items(a: string, c: var TItemsClosure): char =
|
||||
# case c.state
|
||||
# of 0: goto L0 # very difficult without goto!
|
||||
# of 1: goto L1 # can be implemented by GCC's computed gotos
|
||||
#
|
||||
# block L0:
|
||||
# c.i = 0
|
||||
# while c.i < length(a):
|
||||
# c.state = 1
|
||||
# return a[i]
|
||||
# block L1: inc(c.i)
|
||||
#
|
||||
# More efficient, but not implementable::
|
||||
#
|
||||
# type
|
||||
# TItemsClosure = record
|
||||
# i: int
|
||||
# pc: pointer
|
||||
#
|
||||
# proc items(a: string, c: var TItemsClosure): char =
|
||||
# goto c.pc
|
||||
# c.i = 0
|
||||
# while c.i < length(a):
|
||||
# c.pc = label1
|
||||
# return a[i]
|
||||
# label1: inc(c.i)
|
||||
#
|
||||
|
||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
||||
result[0] = PTransNode(le)
|
||||
|
|
@ -178,15 +129,6 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
|||
if result != nil: return
|
||||
tc = tc.next
|
||||
result = b
|
||||
when false:
|
||||
case b.sym.kind
|
||||
of skConst, skEnumField:
|
||||
if sfFakeConst notin b.sym.flags:
|
||||
if skipTypes(b.sym.typ, abstractInst).kind notin ConstantDataTypes:
|
||||
result = getConstExpr(c.module, b)
|
||||
if result == nil: InternalError(b.info, "transformSym: const")
|
||||
else:
|
||||
nil
|
||||
|
||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
result = PTransNode(transformSymAux(c, n))
|
||||
|
|
@ -378,20 +320,6 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
|||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||
# addr ( deref ( x )) --> x
|
||||
result = PTransNode(n.sons[0].sons[0])
|
||||
|
||||
proc generateThunk(c: PTransf, prc: PNode, dest: PType): PNode =
|
||||
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
|
||||
## a closure.
|
||||
|
||||
# we cannot generate a proper thunk here for GC-safety reasons (see internal
|
||||
# documentation):
|
||||
if gCmd == cmdCompileToEcmaScript: return prc
|
||||
result = newNodeIT(nkClosure, prc.info, dest)
|
||||
var conv = newNodeIT(nkHiddenStdConv, prc.info, dest)
|
||||
conv.add(emptyNode)
|
||||
conv.add(prc)
|
||||
result.add(conv)
|
||||
result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
|
||||
|
||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
# numeric types need range checks:
|
||||
|
|
@ -466,12 +394,6 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
|||
result[0] = transform(c, n.sons[1])
|
||||
else:
|
||||
result = transform(c, n.sons[1])
|
||||
of tyProc:
|
||||
if dest.callConv == ccClosure and source.callConv == ccDefault:
|
||||
let x = transform(c, n.sons[1]).pnode
|
||||
result = generateThunk(c, x, dest).ptransnode
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyGenericParam, tyOrdinal, tyTypeClass:
|
||||
result = transform(c, n.sons[1])
|
||||
# happens sometimes for generated assignments, etc.
|
||||
|
|
@ -657,21 +579,23 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
result = PTransNode(n)
|
||||
of nkBracketExpr: result = transformArrayAccess(c, n)
|
||||
of procDefs:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
var s = n.sons[namePos].sym
|
||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||
if s.ast.sons[bodyPos] != n.sons[bodyPos]:
|
||||
# somehow this can happen ... :-/
|
||||
s.ast.sons[bodyPos] = n.sons[bodyPos]
|
||||
n.sons[bodyPos] = liftLambdas(n)
|
||||
if n.kind == nkMethodDef: methodDef(s, false)
|
||||
when false:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
var s = n.sons[namePos].sym
|
||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||
if s.ast.sons[bodyPos] != n.sons[bodyPos]:
|
||||
# somehow this can happen ... :-/
|
||||
s.ast.sons[bodyPos] = n.sons[bodyPos]
|
||||
#n.sons[bodyPos] = liftLambdas(s, n)
|
||||
#if n.kind == nkMethodDef: methodDef(s, false)
|
||||
result = PTransNode(n)
|
||||
of nkMacroDef:
|
||||
# XXX no proper closure support yet:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
var s = n.sons[namePos].sym
|
||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||
if n.kind == nkMethodDef: methodDef(s, false)
|
||||
when false:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
var s = n.sons[namePos].sym
|
||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||
if n.kind == nkMethodDef: methodDef(s, false)
|
||||
result = PTransNode(n)
|
||||
of nkForStmt:
|
||||
inc c.inLoop
|
||||
|
|
@ -735,38 +659,57 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
result = PTransNode(cnst) # do not miss an optimization
|
||||
|
||||
proc processTransf(context: PPassContext, n: PNode): PNode =
|
||||
proc processTransf(c: PTransf, n: PNode): PNode =
|
||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||
# this step! We have to rely that the semantic pass transforms too errornous
|
||||
# nodes into an empty node.
|
||||
if passes.skipCodegen(n) or context.fromCache or nfTransf in n.flags: return n
|
||||
var c = PTransf(context)
|
||||
if passes.skipCodegen(n) or c.fromCache or nfTransf in n.flags: return n
|
||||
pushTransCon(c, newTransCon(getCurrOwner(c)))
|
||||
result = PNode(transform(c, n))
|
||||
popTransCon(c)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc openTransf(module: PSym, filename: string): PPassContext =
|
||||
var n: PTransf
|
||||
new(n)
|
||||
n.contSyms = @[]
|
||||
n.breakSyms = @[]
|
||||
n.module = module
|
||||
result = n
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
new(result)
|
||||
result.contSyms = @[]
|
||||
result.breakSyms = @[]
|
||||
result.module = module
|
||||
|
||||
proc openTransfCached(module: PSym, filename: string,
|
||||
rd: PRodReader): PPassContext =
|
||||
result = openTransf(module, filename)
|
||||
for m in items(rd.methods): methodDef(m, true)
|
||||
when false:
|
||||
proc openTransfCached(module: PSym, filename: string,
|
||||
rd: PRodReader): PPassContext =
|
||||
result = openTransf(module, filename)
|
||||
for m in items(rd.methods): methodDef(m, true)
|
||||
|
||||
proc transfPass(): TPass =
|
||||
initPass(result)
|
||||
result.open = openTransf
|
||||
result.openCached = openTransfCached
|
||||
result.process = processTransf
|
||||
result.close = processTransf # we need to process generics too!
|
||||
proc transfPass(): TPass =
|
||||
initPass(result)
|
||||
result.open = openTransf
|
||||
result.openCached = openTransfCached
|
||||
result.process = processTransf
|
||||
result.close = processTransf # we need to process generics too!
|
||||
|
||||
proc transform*(module: PSym, n: PNode): PNode =
|
||||
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||
if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = processTransf(c, n)
|
||||
if prc.kind != skMacro:
|
||||
# XXX no closures yet for macros:
|
||||
result = liftLambdas(prc, result)
|
||||
if prc.kind == skMethod: methodDef(prc, false)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = processTransf(c, n)
|
||||
result = liftLambdasForTopLevel(module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc transformExpr*(module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue