further steps for closure support; added 'system.rawProc', 'system.rawEnv'

This commit is contained in:
Araq 2012-02-08 22:56:31 +01:00
commit f3f3fc01aa
4 changed files with 68 additions and 13 deletions

View file

@ -257,28 +257,57 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
assert(a.kind == nkIdentDefs) assert(a.kind == nkIdentDefs)
assert(a.sons[0].kind == nkSym) #assert(a.sons[0].kind == nkSym) can happen for transformed vars
var v = a.sons[0].sym
if a.sons[2].kind != nkEmpty: if a.sons[2].kind != nkEmpty:
result = evalAux(c, a.sons[2], {}) result = evalAux(c, a.sons[2], {})
if isSpecial(result): return if isSpecial(result): return
else: else:
result = getNullValue(a.sons[0].typ, a.sons[0].info) result = getNullValue(a.sons[0].typ, a.sons[0].info)
if a.sons[0].kind == nkSym:
var v = a.sons[0].sym
IdNodeTablePut(c.tos.mapping, v, result) IdNodeTablePut(c.tos.mapping, v, result)
else:
# assign to a.sons[0]:
var x = result
result = evalAux(c, a.sons[0], {})
if isSpecial(result): return
myreset(x)
x.kind = result.kind
x.typ = result.typ
case x.kind
of nkCharLit..nkInt64Lit: x.intVal = result.intVal
of nkFloatLit..nkFloat64Lit: x.floatVal = result.floatVal
of nkStrLit..nkTripleStrLit: x.strVal = result.strVal
of nkIdent: x.ident = result.ident
of nkSym: x.sym = result.sym
else:
if x.kind notin {nkEmpty..nkNilLit}:
discardSons(x)
for i in countup(0, sonsLen(result) - 1): addSon(x, result.sons[i])
result = emptyNode result = emptyNode
proc evalCall(c: PEvalContext, n: PNode): PNode = proc evalCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
var prc = result
# bind the actual params to the local parameter of a new binding
var d = newStackFrame() var d = newStackFrame()
d.call = n d.call = n
var prc = n.sons[0]
let isClosure = prc.kind == nkClosure
setlen(d.params, sonsLen(n) + ord(isClosure))
if isClosure:
#debug prc
result = evalAux(c, prc.sons[1], {efLValue})
if isSpecial(result): return
d.params[sonsLen(n)] = result
result = evalAux(c, prc.sons[0], {})
else:
result = evalAux(c, prc, {})
if isSpecial(result): return
prc = result
# bind the actual params to the local parameter of a new binding
if prc.kind == nkSym: if prc.kind == nkSym:
d.prc = prc.sym d.prc = prc.sym
if not (prc.sym.kind in {skProc, skConverter}): if prc.sym.kind notin {skProc, skConverter}:
InternalError(n.info, "evalCall") InternalError(n.info, "evalCall")
setlen(d.params, sonsLen(n))
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], {}) result = evalAux(c, n.sons[i], {})
if isSpecial(result): return if isSpecial(result): return
@ -308,6 +337,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
result = copyTree(result) result = copyTree(result)
if result != nil: return if result != nil: return
x = x.next x = x.next
internalError(sym.info, "cannot eval " & sym.name.s)
result = raiseCannotEval(nil, sym.info) result = raiseCannotEval(nil, sym.info)
#result = emptyNode #result = emptyNode
@ -1165,7 +1195,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if isSpecial(result): return if isSpecial(result): return
addSon(a, result) addSon(a, result)
result = a result = a
of nkPar: of nkPar, nkClosure:
var a = copyTree(n) var a = copyTree(n)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i] var it = n.sons[i]
@ -1218,6 +1248,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkLambda, nkContinueStmt, nkIdent: nkLambda, nkContinueStmt, nkIdent:
result = raiseCannotEval(c, n.info) result = raiseCannotEval(c, n.info)
of nkRefTy:
result = evalAux(c, n.sons[0], flags)
else: InternalError(n.info, "evalAux: " & $n.kind) else: InternalError(n.info, "evalAux: " & $n.kind)
if result == nil: if result == nil:
InternalError(n.info, "evalAux: returned nil " & $n.kind) InternalError(n.info, "evalAux: returned nil " & $n.kind)

View file

@ -10,7 +10,7 @@
# This include file implements lambda lifting for the transformator. # This include file implements lambda lifting for the transformator.
const const
declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef,
nkConverterDef} nkConverterDef}
procDefs = {nkLambda} + declarativeDefs procDefs = {nkLambda} + declarativeDefs
@ -79,9 +79,10 @@ proc replaceVars(c: PTransf, n: PNode, outerProc, env: PSym) =
proc addHiddenParam(routine: PSym, param: PSym) = proc addHiddenParam(routine: PSym, param: PSym) =
var params = routine.ast.sons[paramsPos] var params = routine.ast.sons[paramsPos]
let L = params.len-1 let L = params.len-1
param.position = L
if L >= 0: if L >= 0:
# update if we already added a hidden parameter: # update if we already added a hidden parameter:
if params.sons[L].kind == nkSym and params.sons[L].sym.kind == skTemp: if params.sons[L].kind == nkSym and params.sons[L].sym.kind == skParam:
params.sons[L].sym = param params.sons[L].sym = param
return return
addSon(params, newSymNode(param)) addSon(params, newSymNode(param))
@ -122,6 +123,7 @@ proc transformInnerProcs(c: PTransf, n: PNode, outerProc, env: PSym) =
else: else:
# inner proc could capture outer vars: # inner proc could capture outer vars:
var param = newTemp(c, env.typ, n.info) var param = newTemp(c, env.typ, n.info)
param.kind = skParam
# recursive calls go through (f, hiddenParam): # recursive calls go through (f, hiddenParam):
IdNodeTablePut(c.transCon.mapping, innerProc, IdNodeTablePut(c.transCon.mapping, innerProc,

View file

@ -626,6 +626,13 @@ proc transform(c: PTransf, n: PNode): PTransNode =
if n.sons[namePos].kind == nkSym: if n.sons[namePos].kind == nkSym:
let x = transformSym(c, n.sons[namePos]) let x = transformSym(c, n.sons[namePos])
if x.pnode.kind == nkClosure: result = x if x.pnode.kind == nkClosure: result = x
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)
result = PTransNode(n)
of nkForStmt: result = transformFor(c, n) of nkForStmt: result = transformFor(c, n)
of nkCaseStmt: result = transformCase(c, n) of nkCaseStmt: result = transformCase(c, n)
of nkContinueStmt: of nkContinueStmt:

View file

@ -1955,6 +1955,20 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## can be used to mark a condition to be unlikely. This is a hint for the ## can be used to mark a condition to be unlikely. This is a hint for the
## optimizer. ## optimizer.
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
## retrieves the raw proc pointer of the closure `x`. This is
## useful for interfacing closures with C.
{.emit: """
`result` = `x`.ClPrc;
""".}
proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
## retrieves the raw environment pointer of the closure `x`. This is
## useful for interfacing closures with C.
{.emit: """
`result` = `x`.ClEnv;
""".}
elif defined(ecmaScript) or defined(NimrodVM): elif defined(ecmaScript) or defined(NimrodVM):
# Stubs: # Stubs:
proc GC_disable() = nil proc GC_disable() = nil