From f3f3fc01aa4d7ff36c8e5865d5e7a234636c42b8 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Feb 2012 22:56:31 +0100 Subject: further steps for closure support; added 'system.rawProc', 'system.rawEnv' --- compiler/evals.nim | 54 ++++++++++++++++++++++++++++++++++++---------- compiler/lambdalifting.nim | 6 ++++-- compiler/transf.nim | 7 ++++++ lib/system.nim | 14 ++++++++++++ 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/compiler/evals.nim b/compiler/evals.nim index 311b01b84..cc223e13d 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -257,28 +257,57 @@ proc evalVar(c: PEvalContext, n: PNode): PNode = var a = n.sons[i] if a.kind == nkCommentStmt: continue assert(a.kind == nkIdentDefs) - assert(a.sons[0].kind == nkSym) - var v = a.sons[0].sym + #assert(a.sons[0].kind == nkSym) can happen for transformed vars if a.sons[2].kind != nkEmpty: result = evalAux(c, a.sons[2], {}) if isSpecial(result): return else: 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 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() 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: d.prc = prc.sym - if not (prc.sym.kind in {skProc, skConverter}): + if prc.sym.kind notin {skProc, skConverter}: InternalError(n.info, "evalCall") - setlen(d.params, sonsLen(n)) for i in countup(1, sonsLen(n) - 1): result = evalAux(c, n.sons[i], {}) if isSpecial(result): return @@ -308,6 +337,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode = result = copyTree(result) if result != nil: return x = x.next + internalError(sym.info, "cannot eval " & sym.name.s) result = raiseCannotEval(nil, sym.info) #result = emptyNode @@ -455,7 +485,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = result = evalVariable(c.tos, s, flags) else: result = evalGlobalVar(c, s, flags) - of skParam: + of skParam: # XXX what about LValue? result = c.tos.params[s.position + 1] of skConst: result = s.ast @@ -1165,7 +1195,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = if isSpecial(result): return addSon(a, result) result = a - of nkPar: + of nkPar, nkClosure: var a = copyTree(n) for i in countup(0, sonsLen(n) - 1): 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, nkLambda, nkContinueStmt, nkIdent: result = raiseCannotEval(c, n.info) + of nkRefTy: + result = evalAux(c, n.sons[0], flags) else: InternalError(n.info, "evalAux: " & $n.kind) if result == nil: InternalError(n.info, "evalAux: returned nil " & $n.kind) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 83885029a..b2c2655b0 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,7 +10,7 @@ # This include file implements lambda lifting for the transformator. const - declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, + declarativeDefs = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef} procDefs = {nkLambda} + declarativeDefs @@ -79,9 +79,10 @@ proc replaceVars(c: PTransf, n: PNode, outerProc, env: PSym) = proc addHiddenParam(routine: PSym, param: PSym) = var params = routine.ast.sons[paramsPos] let L = params.len-1 + param.position = L if L >= 0: # 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 return addSon(params, newSymNode(param)) @@ -122,6 +123,7 @@ proc transformInnerProcs(c: PTransf, n: PNode, outerProc, env: PSym) = else: # inner proc could capture outer vars: var param = newTemp(c, env.typ, n.info) + param.kind = skParam # recursive calls go through (f, hiddenParam): IdNodeTablePut(c.transCon.mapping, innerProc, diff --git a/compiler/transf.nim b/compiler/transf.nim index 509aa9320..70d0771bd 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -626,6 +626,13 @@ proc transform(c: PTransf, n: PNode): PTransNode = if n.sons[namePos].kind == nkSym: let x = transformSym(c, n.sons[namePos]) 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 nkCaseStmt: result = transformCase(c, n) of nkContinueStmt: diff --git a/lib/system.nim b/lib/system.nim index 55abcaea6..bf9250a81 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1954,6 +1954,20 @@ when not defined(EcmaScript) and not defined(NimrodVM): proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} ## can be used to mark a condition to be unlikely. This is a hint for the ## 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): # Stubs: -- cgit 1.4.1-2-gfad0