further steps for closure support; added 'system.rawProc', 'system.rawEnv'
This commit is contained in:
parent
2c4a1dbc0c
commit
f3f3fc01aa
4 changed files with 68 additions and 13 deletions
|
|
@ -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)
|
||||||
IdNodeTablePut(c.tos.mapping, v, result)
|
if a.sons[0].kind == nkSym:
|
||||||
|
var v = a.sons[0].sym
|
||||||
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue