summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/evalffi.nim57
-rwxr-xr-xcompiler/evals.nim17
-rwxr-xr-xkoch.nim2
-rwxr-xr-xtodo.txt9
4 files changed, 53 insertions, 32 deletions
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 66ed3a87e..35659ed26 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -34,19 +34,25 @@ proc getDll(cache: var TDllCache; dll: string): pointer =
     cache[dll] = result
 
 proc importcSymbol*(sym: PSym): PNode =
-  let lib = sym.annex
-  if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
-    InternalError("dynlib needs to be a string literal for the REPL")
-  
-  let dllpath = if lib.isNil: libcDll else: lib.path.strVal
-  let dllhandle = gDllCache.getDll(dllpath)
   let name = ropeToStr(sym.loc.r)
-  let theAddr = dllhandle.checkedSymAddr(name)
   
   # the AST does not support untyped pointers directly, so we use an nkIntLit
   # that contains the address instead:
   result = newNodeIT(nkIntLit, sym.info, sym.typ)
-  result.intVal = cast[TAddress](theAddr)
+  case name
+  of "stdin":  result.intVal = cast[TAddress](system.stdin)
+  of "stdout": result.intVal = cast[TAddress](system.stdout)
+  of "stderr": result.intVal = cast[TAddress](system.stderr)
+  else:
+    let lib = sym.annex
+    if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
+      InternalError(sym.info, "dynlib needs to be a string literal for the REPL")
+    
+    let dllpath = if lib.isNil: libcDll else: lib.path.strVal
+    let dllhandle = gDllCache.getDll(dllpath)
+    let theAddr = dllhandle.checkedSymAddr(name)
+    
+    result.intVal = cast[TAddress](theAddr)
 
 proc mapType(t: ast.PType): ptr libffi.TType =
   if t == nil: return addr libffi.type_void
@@ -63,8 +69,10 @@ proc mapType(t: ast.PType): ptr libffi.TType =
   of tyFloat, tyFloat64: result = addr libffi.type_double
   of tyFloat32: result = addr libffi.type_float
   of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
-     tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr:
+     tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
     result = addr libffi.type_pointer
+  of tyDistinct:
+    result = mapType(t.sons[0])
   else:
     InternalError("cannot map type to FFI")
   # too risky:
@@ -80,12 +88,12 @@ proc mapCallConv(cc: TCallingConvention): TABI =
 template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
 template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
 
-proc pack(v: PNode): pointer =
+proc pack(v: PNode, typ: PType): pointer =
   template awr(T, v: expr) {.immediate, dirty.} =
     result = alloc0(sizeof(T))
     wr(T, result, v)
 
-  case v.typ.kind
+  case typ.kind
   of tyBool: awr(bool, v.intVal != 0)
   of tyChar: awr(char, v.intVal.chr)
   of tyInt:  awr(int, v.intVal.int)
@@ -120,6 +128,10 @@ proc pack(v: PNode): pointer =
       result = alloc0(sizeof(pointer))
     else:
       awr(cstring, cstring(v.strVal))
+  of tyNil:
+    result = alloc0(sizeof(pointer))
+  of tyDistinct, tyGenericInst:
+    result = pack(v, typ.sons[0])
   else:
     InternalError("cannot map value to FFI " & typeToString(v.typ))
 
@@ -168,31 +180,36 @@ proc unpack(x: pointer, typ: PType, info: TLineInfo): PNode =
       result = newNodeIT(nkNilLit, info, typ)
     else:
       aws(nkStrLit, $p)
+  of tyNil: result = newNodeIT(nkNilLit, info, typ)
+  of tyDistinct, tyGenericInst:
+    result = unpack(x, typ.sons[0], info)
   else:
     InternalError("cannot map value from FFI " & typeToString(typ))
 
 proc callForeignFunction*(call: PNode): PNode =
   InternalAssert call.sons[0].kind == nkIntLit
-  let typ = call.sons[0].typ
   
   var cif: TCif
   var sig: TParamList
-  for i in 1..typ.len-1: sig[i-1] = mapType(typ.sons[i])
+  # use the arguments' types for varargs support:
+  for i in 1..call.len-1: sig[i-1] = mapType(call.sons[i].typ)
   
-  if prep_cif(cif, mapCallConv(typ.callConv), cuint(typ.len-1), 
+  let typ = call.sons[0].typ
+  if prep_cif(cif, mapCallConv(typ.callConv), cuint(call.len-1), 
               mapType(typ.sons[0]), sig) != OK:
     InternalError(call.info, "error in FFI call")
   
   var args: TArgList
   let fn = cast[pointer](call.sons[0].intVal)
-  for i in 0 .. call.len-1:
-    args[i] = pack(call.sons[i+1])
-  let retVal = alloc(typ.sons[0].getSize.int)
+  for i in 1 .. call.len-1:
+    args[i-1] = pack(call.sons[i], call.sons[i].typ)
+  let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
+               else: alloc(typ.sons[0].getSize.int)
 
   libffi.call(cif, fn, retVal, args)
   
-  if isEmptyType(typ.sons[0]): result = emptyNode
+  if retVal.isNil: result = emptyNode
   else: result = unpack(retVal, typ.sons[0], call.info)
 
-  dealloc retVal
-  for i in countdown(call.len-1, 0): dealloc args[i]
+  if retVal != nil: dealloc retVal
+  for i in countdown(call.len-2, 0): dealloc args[i]
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 535d9aebd..ab6218be0 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -339,16 +339,15 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
       if not aliasNeeded(result, flags): 
         result = copyTree(result)
     else:
+      when hasFFI:
+        if sfImportc in s.flags:
+          result = importcSymbol(s)
+          IdNodeTablePut(c.globals, s, result)
+          return result
+      
       result = s.ast
       if result == nil or result.kind == nkEmpty:
-        when hasFFI:
-          # for 'stdin' etc. we need to support 'importc' for variables:
-          if sfImportc in s.flags:
-            result = importcSymbol(s)
-          else:
-            result = getNullValue(s.typ, s.info)
-        else:
-          result = getNullValue(s.typ, s.info)
+        result = getNullValue(s.typ, s.info)
       else:
         result = evalAux(c, result, {})
         if isSpecial(result): return
@@ -392,7 +391,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
       var newCall = newNodeI(nkCall, n.info, n.len)
       newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
       for i in 1 .. <n.len:
-        newCall.sons[i] = d.params[i-1]
+        newCall.sons[i] = d.params[i]
       return callForeignFunction(newCall)
   
   pushStackFrame(c, d)
diff --git a/koch.nim b/koch.nim
index 029e8a733..b01de94cb 100755
--- a/koch.nim
+++ b/koch.nim
@@ -215,7 +215,7 @@ when defined(withUpdate):
       if errcode == 0:
         if output == "":
           # No changes
-          echo("No update. Exiting..")
+          echo("No update. Exiting...")
           return
         else:
           echo("Fetching updates from repo...")
diff --git a/todo.txt b/todo.txt
index 3d8859fc2..2a6a45370 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,9 +1,12 @@
 version 0.9.2
 =============
 
+- FFI:
+  * proper byte buffers
+  * support for arrays
+  * support for tuples/objects
+  * make system.nim aware of nimffi
 - fix closure bug finally
-- test&finish first class iterators:
-  * nested iterators
 - fix marshal bug
 - investigate nimgame bug
 
@@ -11,6 +14,8 @@ version 0.9.2
 version 0.9.X
 =============
 
+- test&finish first class iterators:
+  * nested iterators
 - implement the missing features wrt inheritance
 - implement generic methods
 - improve the compiler as a service