small examples work with the FFI
This commit is contained in:
parent
3e514cd5dc
commit
c73d9fdd4c
4 changed files with 53 additions and 32 deletions
|
|
@ -34,18 +34,24 @@ proc getDll(cache: var TDllCache; dll: string): pointer =
|
||||||
cache[dll] = result
|
cache[dll] = result
|
||||||
|
|
||||||
proc importcSymbol*(sym: PSym): PNode =
|
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 name = ropeToStr(sym.loc.r)
|
||||||
let theAddr = dllhandle.checkedSymAddr(name)
|
|
||||||
|
|
||||||
# the AST does not support untyped pointers directly, so we use an nkIntLit
|
# the AST does not support untyped pointers directly, so we use an nkIntLit
|
||||||
# that contains the address instead:
|
# that contains the address instead:
|
||||||
result = newNodeIT(nkIntLit, sym.info, sym.typ)
|
result = newNodeIT(nkIntLit, sym.info, sym.typ)
|
||||||
|
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)
|
result.intVal = cast[TAddress](theAddr)
|
||||||
|
|
||||||
proc mapType(t: ast.PType): ptr libffi.TType =
|
proc mapType(t: ast.PType): ptr libffi.TType =
|
||||||
|
|
@ -63,8 +69,10 @@ proc mapType(t: ast.PType): ptr libffi.TType =
|
||||||
of tyFloat, tyFloat64: result = addr libffi.type_double
|
of tyFloat, tyFloat64: result = addr libffi.type_double
|
||||||
of tyFloat32: result = addr libffi.type_float
|
of tyFloat32: result = addr libffi.type_float
|
||||||
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
|
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
|
result = addr libffi.type_pointer
|
||||||
|
of tyDistinct:
|
||||||
|
result = mapType(t.sons[0])
|
||||||
else:
|
else:
|
||||||
InternalError("cannot map type to FFI")
|
InternalError("cannot map type to FFI")
|
||||||
# too risky:
|
# too risky:
|
||||||
|
|
@ -80,12 +88,12 @@ proc mapCallConv(cc: TCallingConvention): TABI =
|
||||||
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
|
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
|
||||||
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
|
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.} =
|
template awr(T, v: expr) {.immediate, dirty.} =
|
||||||
result = alloc0(sizeof(T))
|
result = alloc0(sizeof(T))
|
||||||
wr(T, result, v)
|
wr(T, result, v)
|
||||||
|
|
||||||
case v.typ.kind
|
case typ.kind
|
||||||
of tyBool: awr(bool, v.intVal != 0)
|
of tyBool: awr(bool, v.intVal != 0)
|
||||||
of tyChar: awr(char, v.intVal.chr)
|
of tyChar: awr(char, v.intVal.chr)
|
||||||
of tyInt: awr(int, v.intVal.int)
|
of tyInt: awr(int, v.intVal.int)
|
||||||
|
|
@ -120,6 +128,10 @@ proc pack(v: PNode): pointer =
|
||||||
result = alloc0(sizeof(pointer))
|
result = alloc0(sizeof(pointer))
|
||||||
else:
|
else:
|
||||||
awr(cstring, cstring(v.strVal))
|
awr(cstring, cstring(v.strVal))
|
||||||
|
of tyNil:
|
||||||
|
result = alloc0(sizeof(pointer))
|
||||||
|
of tyDistinct, tyGenericInst:
|
||||||
|
result = pack(v, typ.sons[0])
|
||||||
else:
|
else:
|
||||||
InternalError("cannot map value to FFI " & typeToString(v.typ))
|
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)
|
result = newNodeIT(nkNilLit, info, typ)
|
||||||
else:
|
else:
|
||||||
aws(nkStrLit, $p)
|
aws(nkStrLit, $p)
|
||||||
|
of tyNil: result = newNodeIT(nkNilLit, info, typ)
|
||||||
|
of tyDistinct, tyGenericInst:
|
||||||
|
result = unpack(x, typ.sons[0], info)
|
||||||
else:
|
else:
|
||||||
InternalError("cannot map value from FFI " & typeToString(typ))
|
InternalError("cannot map value from FFI " & typeToString(typ))
|
||||||
|
|
||||||
proc callForeignFunction*(call: PNode): PNode =
|
proc callForeignFunction*(call: PNode): PNode =
|
||||||
InternalAssert call.sons[0].kind == nkIntLit
|
InternalAssert call.sons[0].kind == nkIntLit
|
||||||
let typ = call.sons[0].typ
|
|
||||||
|
|
||||||
var cif: TCif
|
var cif: TCif
|
||||||
var sig: TParamList
|
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:
|
mapType(typ.sons[0]), sig) != OK:
|
||||||
InternalError(call.info, "error in FFI call")
|
InternalError(call.info, "error in FFI call")
|
||||||
|
|
||||||
var args: TArgList
|
var args: TArgList
|
||||||
let fn = cast[pointer](call.sons[0].intVal)
|
let fn = cast[pointer](call.sons[0].intVal)
|
||||||
for i in 0 .. call.len-1:
|
for i in 1 .. call.len-1:
|
||||||
args[i] = pack(call.sons[i+1])
|
args[i-1] = pack(call.sons[i], call.sons[i].typ)
|
||||||
let retVal = alloc(typ.sons[0].getSize.int)
|
let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
|
||||||
|
else: alloc(typ.sons[0].getSize.int)
|
||||||
|
|
||||||
libffi.call(cif, fn, retVal, args)
|
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)
|
else: result = unpack(retVal, typ.sons[0], call.info)
|
||||||
|
|
||||||
dealloc retVal
|
if retVal != nil: dealloc retVal
|
||||||
for i in countdown(call.len-1, 0): dealloc args[i]
|
for i in countdown(call.len-2, 0): dealloc args[i]
|
||||||
|
|
|
||||||
|
|
@ -339,15 +339,14 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||||
if not aliasNeeded(result, flags):
|
if not aliasNeeded(result, flags):
|
||||||
result = copyTree(result)
|
result = copyTree(result)
|
||||||
else:
|
else:
|
||||||
result = s.ast
|
|
||||||
if result == nil or result.kind == nkEmpty:
|
|
||||||
when hasFFI:
|
when hasFFI:
|
||||||
# for 'stdin' etc. we need to support 'importc' for variables:
|
|
||||||
if sfImportc in s.flags:
|
if sfImportc in s.flags:
|
||||||
result = importcSymbol(s)
|
result = importcSymbol(s)
|
||||||
else:
|
IdNodeTablePut(c.globals, s, result)
|
||||||
result = getNullValue(s.typ, s.info)
|
return result
|
||||||
else:
|
|
||||||
|
result = s.ast
|
||||||
|
if result == nil or result.kind == nkEmpty:
|
||||||
result = getNullValue(s.typ, s.info)
|
result = getNullValue(s.typ, s.info)
|
||||||
else:
|
else:
|
||||||
result = evalAux(c, result, {})
|
result = evalAux(c, result, {})
|
||||||
|
|
@ -392,7 +391,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||||
var newCall = newNodeI(nkCall, n.info, n.len)
|
var newCall = newNodeI(nkCall, n.info, n.len)
|
||||||
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
||||||
for i in 1 .. <n.len:
|
for i in 1 .. <n.len:
|
||||||
newCall.sons[i] = d.params[i-1]
|
newCall.sons[i] = d.params[i]
|
||||||
return callForeignFunction(newCall)
|
return callForeignFunction(newCall)
|
||||||
|
|
||||||
pushStackFrame(c, d)
|
pushStackFrame(c, d)
|
||||||
|
|
|
||||||
2
koch.nim
2
koch.nim
|
|
@ -215,7 +215,7 @@ when defined(withUpdate):
|
||||||
if errcode == 0:
|
if errcode == 0:
|
||||||
if output == "":
|
if output == "":
|
||||||
# No changes
|
# No changes
|
||||||
echo("No update. Exiting..")
|
echo("No update. Exiting...")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
echo("Fetching updates from repo...")
|
echo("Fetching updates from repo...")
|
||||||
|
|
|
||||||
9
todo.txt
9
todo.txt
|
|
@ -1,9 +1,12 @@
|
||||||
version 0.9.2
|
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
|
- fix closure bug finally
|
||||||
- test&finish first class iterators:
|
|
||||||
* nested iterators
|
|
||||||
- fix marshal bug
|
- fix marshal bug
|
||||||
- investigate nimgame bug
|
- investigate nimgame bug
|
||||||
|
|
||||||
|
|
@ -11,6 +14,8 @@ version 0.9.2
|
||||||
version 0.9.X
|
version 0.9.X
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
- test&finish first class iterators:
|
||||||
|
* nested iterators
|
||||||
- implement the missing features wrt inheritance
|
- implement the missing features wrt inheritance
|
||||||
- implement generic methods
|
- implement generic methods
|
||||||
- improve the compiler as a service
|
- improve the compiler as a service
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue