summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/evals.nim54
-rw-r--r--compiler/lambdalifting.nim6
-rwxr-xr-xcompiler/transf.nim7
-rwxr-xr-xlib/system.nim14
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: