mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 22:35:24 +00:00
next steps for FFI at compile time
This commit is contained in:
@@ -279,6 +279,13 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
|
||||
for i in 0 .. < result.len:
|
||||
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
|
||||
|
||||
proc canonNodeKind(k: TNodeKind): TNodeKind =
|
||||
case k
|
||||
of nkCharLit..nkUInt64Lit: result = nkIntLit
|
||||
of nkFloatLit..nkFloat128Lit: result = nkFloatLit
|
||||
of nkStrLit..nkTripleStrLit: result = nkStrLit
|
||||
else: result = k
|
||||
|
||||
proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
template aw(k, v, field: expr) {.immediate, dirty.} =
|
||||
if n.isNil:
|
||||
@@ -287,7 +294,8 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
else:
|
||||
# check we have the right field:
|
||||
result = n
|
||||
if result.kind != k:
|
||||
if result.kind.canonNodeKind != k.canonNodeKind:
|
||||
echo "expected ", k, " but got ", result.kind
|
||||
GlobalError(n.info, "cannot map value from FFI")
|
||||
result.field = v
|
||||
|
||||
@@ -309,15 +317,15 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
of tyBool: awi(nkIntLit, rd(bool, x).ord)
|
||||
of tyChar: awi(nkIntLit, rd(char, x).ord)
|
||||
of tyInt: awi(nkIntLit, rd(int, x))
|
||||
of tyInt8: awi(nkIntLit, rd(int8, x))
|
||||
of tyInt16: awi(nkIntLit, rd(int16, x))
|
||||
of tyInt32: awi(nkIntLit, rd(int32, x))
|
||||
of tyInt64: awi(nkIntLit, rd(int64, x))
|
||||
of tyUInt: awi(nkIntLit, rd(uint, x).biggestInt)
|
||||
of tyUInt8: awi(nkIntLit, rd(uint8, x).biggestInt)
|
||||
of tyUInt16: awi(nkIntLit, rd(uint16, x).biggestInt)
|
||||
of tyUInt32: awi(nkIntLit, rd(uint32, x).biggestInt)
|
||||
of tyUInt64: awi(nkIntLit, rd(uint64, x).biggestInt)
|
||||
of tyInt8: awi(nkInt8Lit, rd(int8, x))
|
||||
of tyInt16: awi(nkInt16Lit, rd(int16, x))
|
||||
of tyInt32: awi(nkInt32Lit, rd(int32, x))
|
||||
of tyInt64: awi(nkInt64Lit, rd(int64, x))
|
||||
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
|
||||
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
|
||||
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
|
||||
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
|
||||
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
|
||||
of tyEnum:
|
||||
case typ.getSize
|
||||
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
|
||||
@@ -327,8 +335,8 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
else:
|
||||
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
|
||||
of tyFloat: awf(nkFloatLit, rd(float, x))
|
||||
of tyFloat32: awf(nkFloatLit, rd(float32, x))
|
||||
of tyFloat64: awf(nkFloatLit, rd(float64, x))
|
||||
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
|
||||
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
|
||||
of tyPointer, tyProc:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
@@ -339,7 +347,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n != nil and n.kind == nkPtrLit:
|
||||
elif n == nil or n.kind == nkPtrLit:
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
elif n != nil and n.len == 1:
|
||||
n.sons[0] = unpack(rd(pointer, x), typ.sons[0], n.sons[0])
|
||||
@@ -363,6 +371,14 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
|
||||
# XXX what to do with 'array' here?
|
||||
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
|
||||
|
||||
proc fficast*(x: PNode, destTyp: PType): PNode =
|
||||
# we play safe here and allocate the max possible size:
|
||||
let allocSize = max(packSize(x, x.typ), packSize(x, destTyp))
|
||||
var a = alloc0(allocSize)
|
||||
pack(x, x.typ, a)
|
||||
result = unpack(a, destTyp, nil)
|
||||
dealloc a
|
||||
|
||||
proc callForeignFunction*(call: PNode): PNode =
|
||||
InternalAssert call.sons[0].kind == nkPtrLit
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ proc newEvalContext*(module: PSym, filename: string,
|
||||
new(result)
|
||||
result.module = module
|
||||
result.mode = mode
|
||||
result.features = {allowFFI}
|
||||
initIdNodeTable(result.globals)
|
||||
|
||||
proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} =
|
||||
@@ -90,7 +91,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} =
|
||||
proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
|
||||
|
||||
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
|
||||
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
|
||||
result = newNodeI(nkExceptBranch, info)
|
||||
# creating a nkExceptBranch without sons
|
||||
# means that it could not be evaluated
|
||||
@@ -351,7 +352,7 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
|
||||
result = copyTree(result)
|
||||
else:
|
||||
when hasFFI:
|
||||
if sfImportc in s.flags:
|
||||
if sfImportc in s.flags and allowFFI in c.features:
|
||||
result = importcSymbol(s)
|
||||
IdNodeTablePut(c.globals, s, result)
|
||||
return result
|
||||
@@ -398,7 +399,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
|
||||
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
|
||||
|
||||
when hasFFI:
|
||||
if sfImportc in prc.sym.flags:
|
||||
if sfImportc in prc.sym.flags and allowFFI in c.features:
|
||||
var newCall = newNodeI(nkCall, n.info, n.len)
|
||||
newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
|
||||
for i in 1 .. <n.len:
|
||||
@@ -549,7 +550,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
of skConst: result = s.ast
|
||||
of skEnumField: result = newIntNodeT(s.position, n)
|
||||
else: result = nil
|
||||
const mask = when hasFFI: {sfForward} else: {sfImportc, sfForward}
|
||||
let mask = if hasFFI and allowFFI in c.features: {sfForward}
|
||||
else: {sfImportc, sfForward}
|
||||
if result == nil or mask * s.flags != {}:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
@@ -650,9 +652,13 @@ proc evalConv(c: PEvalContext, n: PNode): PNode =
|
||||
|
||||
proc evalCast(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
if allowCast in c.features:
|
||||
# XXX we need better checking here and the new pack/unpack stuff should
|
||||
# be useful for some casts too:
|
||||
result = evalConv(c, n)
|
||||
when hasFFI:
|
||||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
InternalAssert result.typ != nil
|
||||
result = fficast(result, n.typ)
|
||||
else:
|
||||
result = evalConv(c, n)
|
||||
else:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
||||
@@ -1429,7 +1435,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
||||
if sonsLen(result) >= 1:
|
||||
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
|
||||
else:
|
||||
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n))
|
||||
stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
|
||||
|
||||
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||
var p = newEvalContext(module, "", mode)
|
||||
@@ -1474,6 +1480,7 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||
|
||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
||||
var c = newEvalContext(module, filename, emRepl)
|
||||
c.features = {allowCast, allowFFI, allowInfiniteLoops}
|
||||
pushStackFrame(c, newStackFrame())
|
||||
result = c
|
||||
|
||||
|
||||
@@ -153,7 +153,6 @@ proc CommandCompileToEcmaScript =
|
||||
|
||||
proc CommandInteractive =
|
||||
msgs.gErrorMax = high(int) # do not stop after first error
|
||||
incl(gGlobalOptions, optSafeCode)
|
||||
#setTarget(osNimrodVM, cpuNimrodVM)
|
||||
initDefines()
|
||||
DefineSymbol("nimrodvm")
|
||||
|
||||
Reference in New Issue
Block a user