[pypy-commit] pypy ffi-backend: Progress.
arigo
noreply at buildbot.pypy.org
Wed Jun 20 12:29:11 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55726:f0f5830163f0
Date: 2012-06-19 21:36 +0200
http://bitbucket.org/pypy/pypy/changeset/f0f5830163f0/
Log: Progress.
diff --git a/pypy/module/_ffi_backend/__init__.py b/pypy/module/_ffi_backend/__init__.py
--- a/pypy/module/_ffi_backend/__init__.py
+++ b/pypy/module/_ffi_backend/__init__.py
@@ -5,7 +5,11 @@
appleveldefs = {
}
interpleveldefs = {
- 'nonstandard_integer_types':
- 'interp_extra_types.nonstandard_integer_types',
- 'load_library': 'interp_library.load_library',
+ 'nonstandard_integer_types': 'misc.nonstandard_integer_types',
+
+ 'load_library': 'libraryobj.load_library',
+
+ 'new_primitive_type': 'newtype.new_primitive_type',
+
+ 'cast': 'func.cast',
}
diff --git a/pypy/module/_ffi_backend/cdataobj.py b/pypy/module/_ffi_backend/cdataobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/cdataobj.py
@@ -0,0 +1,60 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib import rgc
+
+
+class W_CData(Wrappable):
+ _immutable_ = True
+ cdata = lltype.nullptr(rffi.CCHARP.TO)
+
+ def __init__(self, space, cdata, ctype):
+ from pypy.module._ffi_backend import ctypeobj
+ assert lltype.typeOf(cdata) == rffi.CCHARP
+ assert isinstance(ctype, ctypeobj.W_CType)
+ self.space = space
+ self.cdata = cdata
+ self.ctype = ctype
+
+ def repr(self):
+ return self.space.wrap("<cdata '%s'>" % self.ctype.name)
+
+ def write_raw_integer_data(self, source):
+ size = self.ctype.size
+ for TP, TPP in _prim_unsigned_types:
+ if size == rffi.sizeof(TP):
+ rffi.cast(TPP, self.cdata)[0] = rffi.cast(TP, source)
+ return
+ raise NotImplementedError("bad integer size")
+
+_prim_unsigned_types = unrolling_iterable([
+ (rffi.UCHAR, rffi.UCHARP),
+ (rffi.USHORT, rffi.USHORTP),
+ (rffi.UINT, rffi.UINTP),
+ (rffi.ULONG, rffi.ULONGP),
+ (rffi.ULONGLONG, rffi.ULONGLONGP)])
+
+
+class W_CDataOwn(W_CData):
+
+ def __init__(self, space, size, ctype):
+ cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
+ W_CData.__init__(self, space, cdata, ctype)
+
+ @rgc.must_be_light_finalizer
+ def __del__(self):
+ lltype.free(self.cdata, flavor='raw')
+
+
+W_CData.typedef = TypeDef(
+ '_ffi_backend.CData',
+ __repr__ = interp2app(W_CData.repr),
+ )
+W_CData.acceptable_as_base_class = False
+
+
+def check_cdata(space, w_obj):
+ return space.is_w(space.type(w_obj), space.gettypefor(W_CData))
diff --git a/pypy/module/_ffi_backend/ctypeobj.py b/pypy/module/_ffi_backend/ctypeobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/ctypeobj.py
@@ -0,0 +1,55 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import lltype, rffi
+
+from pypy.module._ffi_backend import cdataobj, misc
+
+
+class W_CType(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, name, size):
+ self.space = space
+ self.name = name
+ self.size = size # size of instances, or -1 if unknown
+
+ def repr(self):
+ space = self.space
+ return space.wrap("<ctype '%s'>" % (self.name,))
+
+ def cast(self, w_ob):
+ raise NotImplementedError
+
+
+class W_CTypePrimitive(W_CType):
+
+ def cast(self, w_ob):
+ space = self.space
+ if cdataobj.check_cdata(space, w_ob):
+ xxx
+ elif space.isinstance_w(w_ob, space.w_str):
+ xxx
+ elif space.is_w(w_ob, space.w_None):
+ value = 0
+ else:
+ value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+ w_cdata = cdataobj.W_CDataOwn(space, self.size, self)
+ w_cdata.write_raw_integer_data(value)
+ return w_cdata
+
+
+class W_CTypePrimitiveChar(W_CTypePrimitive):
+ pass
+
+class W_CTypePrimitiveSigned(W_CTypePrimitive):
+ pass
+
+
+
+W_CType.typedef = TypeDef(
+ '_ffi_backend.CTypeDescr',
+ __repr__ = interp2app(W_CType.repr),
+ )
+W_CType.acceptable_as_base_class = False
diff --git a/pypy/module/_ffi_backend/func.py b/pypy/module/_ffi_backend/func.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/func.py
@@ -0,0 +1,13 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.rpython.lltypesystem import lltype, rffi
+
+from pypy.module._ffi_backend.ctypeobj import W_CType
+
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=W_CType)
+def cast(space, ctype, w_ob):
+ return ctype.cast(w_ob)
diff --git a/pypy/module/_ffi_backend/interp_extra_types.py b/pypy/module/_ffi_backend/interp_extra_types.py
deleted file mode 100644
--- a/pypy/module/_ffi_backend/interp_extra_types.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from pypy.rpython.lltypesystem import lltype, rffi
-
-
-UNSIGNED = 0x1000
-
-TYPES = [
- ("int8_t", 1),
- ("uint8_t", 1 | UNSIGNED),
- ("int16_t", 2),
- ("uint16_t", 2 | UNSIGNED),
- ("int32_t", 4),
- ("uint32_t", 4 | UNSIGNED),
- ("int64_t", 8),
- ("uint64_t", 8 | UNSIGNED),
-
- ("intptr_t", rffi.sizeof(rffi.INTPTR_T)),
- ("uintptr_t", rffi.sizeof(rffi.UINTPTR_T) | UNSIGNED),
- ("ptrdiff_t", rffi.sizeof(rffi.INTPTR_T)), # XXX can it be different?
- ("size_t", rffi.sizeof(rffi.SIZE_T) | UNSIGNED),
- ("ssize_t", rffi.sizeof(rffi.SSIZE_T)),
-]
-
-
-def nonstandard_integer_types(space):
- w_d = space.newdict()
- for name, size in TYPES:
- space.setitem(w_d, space.wrap(name), space.wrap(size))
- return w_d
diff --git a/pypy/module/_ffi_backend/interp_library.py b/pypy/module/_ffi_backend/interp_library.py
deleted file mode 100644
--- a/pypy/module/_ffi_backend/interp_library.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from __future__ import with_statement
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.rdynload import DLLHANDLE, dlopen, dlclose, DLOpenError
-
-
-class W_Library(Wrappable):
- handle = rffi.cast(DLLHANDLE, 0)
-
- def __init__(self, space, filename):
- self.space = space
- with rffi.scoped_str2charp(filename) as ll_libname:
- try:
- self.handle = dlopen(ll_libname)
- except DLOpenError, e:
- raise operationerrfmt(space.w_OSError,
- "cannot load '%s': %s",
- filename, e.msg)
- self.name = filename
-
- def __del__(self):
- h = self.handle
- if h != rffi.cast(DLLHANDLE, 0):
- self.handle = rffi.cast(DLLHANDLE, 0)
- dlclose(h)
-
- def repr(self):
- space = self.space
- return space.wrap("<clibrary '%s'>" % self.name)
-
-
-W_Library.typedef = TypeDef(
- '_ffi_backend.Library',
- __repr__ = interp2app(W_Library.repr),
- )
-
-
- at unwrap_spec(filename=str)
-def load_library(space, filename):
- lib = W_Library(space, filename)
- return space.wrap(lib)
diff --git a/pypy/module/_ffi_backend/libraryobj.py b/pypy/module/_ffi_backend/libraryobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/libraryobj.py
@@ -0,0 +1,45 @@
+from __future__ import with_statement
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rdynload import DLLHANDLE, dlopen, dlclose, DLOpenError
+
+
+class W_Library(Wrappable):
+ handle = rffi.cast(DLLHANDLE, 0)
+
+ def __init__(self, space, filename):
+ self.space = space
+ with rffi.scoped_str2charp(filename) as ll_libname:
+ try:
+ self.handle = dlopen(ll_libname)
+ except DLOpenError, e:
+ raise operationerrfmt(space.w_OSError,
+ "cannot load '%s': %s",
+ filename, e.msg)
+ self.name = filename
+
+ def __del__(self):
+ h = self.handle
+ if h != rffi.cast(DLLHANDLE, 0):
+ self.handle = rffi.cast(DLLHANDLE, 0)
+ dlclose(h)
+
+ def repr(self):
+ space = self.space
+ return space.wrap("<clibrary '%s'>" % self.name)
+
+
+W_Library.typedef = TypeDef(
+ '_ffi_backend.Library',
+ __repr__ = interp2app(W_Library.repr),
+ )
+W_Library.acceptable_as_base_class = False
+
+
+ at unwrap_spec(filename=str)
+def load_library(space, filename):
+ lib = W_Library(space, filename)
+ return space.wrap(lib)
diff --git a/pypy/module/_ffi_backend/misc.py b/pypy/module/_ffi_backend/misc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/misc.py
@@ -0,0 +1,79 @@
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rarithmetic import r_ulonglong
+
+
+UNSIGNED = 0x1000
+
+TYPES = [
+ ("int8_t", 1),
+ ("uint8_t", 1 | UNSIGNED),
+ ("int16_t", 2),
+ ("uint16_t", 2 | UNSIGNED),
+ ("int32_t", 4),
+ ("uint32_t", 4 | UNSIGNED),
+ ("int64_t", 8),
+ ("uint64_t", 8 | UNSIGNED),
+
+ ("intptr_t", rffi.sizeof(rffi.INTPTR_T)),
+ ("uintptr_t", rffi.sizeof(rffi.UINTPTR_T) | UNSIGNED),
+ ("ptrdiff_t", rffi.sizeof(rffi.INTPTR_T)), # XXX can it be different?
+ ("size_t", rffi.sizeof(rffi.SIZE_T) | UNSIGNED),
+ ("ssize_t", rffi.sizeof(rffi.SSIZE_T)),
+]
+
+
+def nonstandard_integer_types(space):
+ w_d = space.newdict()
+ for name, size in TYPES:
+ space.setitem(w_d, space.wrap(name), space.wrap(size))
+ return w_d
+
+# ____________________________________________________________
+
+def as_long_long(space, w_ob, strict):
+ # (possibly) convert and cast a Python object to a long long.
+ # This version accepts a Python int too, and does convertions from
+ # other types of objects. It refuses floats.
+ if space.is_w(space.type(w_ob), space.w_int): # shortcut
+ return space.int_w(w_ob)
+ try:
+ bigint = space.bigint_w(w_ob)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
+ if space.isinstance_w(w_ob, space.w_float):
+ raise
+ bigint = space.bigint_w(space.int(w_ob))
+ try:
+ return bigint.tolonglong()
+ except OverflowError:
+ raise OperationError(space.w_OverflowError,
+ space.wrap("long too big to convert"))
+
+def as_unsigned_long_long(space, w_ob, strict):
+ # (possibly) convert and cast a Python object to an unsigned long long.
+ # This accepts a Python int too, and does convertions from other types of
+ # objects. If 'overflow', complains with OverflowError; if 'not overflow',
+ # mask the result.
+ if space.is_w(space.type(w_ob), space.w_int): # shortcut
+ value = space.int_w(w_ob)
+ if strict and value < 0:
+ raise OperationError(space.w_OverflowError, space.wrap(neg_msg))
+ return r_ulonglong(value)
+ try:
+ bigint = space.bigint_w(w_ob)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
+ if strict and space.isinstance_w(w_ob, space.w_float):
+ raise
+ bigint = space.bigint_w(space.int(w_ob))
+ if strict:
+ try:
+ return bigint.toulonglong()
+ except ValueError:
+ raise OperationError(space.w_OverflowError, space.wrap(neg_msg))
+ else:
+ return bigint.ulonglongmask()
+
+neg_msg = "can't convert negative number to unsigned"
diff --git a/pypy/module/_ffi_backend/newtype.py b/pypy/module/_ffi_backend/newtype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/newtype.py
@@ -0,0 +1,26 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.rpython.lltypesystem import lltype, rffi
+
+from pypy.module._ffi_backend import ctypeobj
+
+
+# ____________________________________________________________
+
+
+PRIMITIVE_TYPES = {}
+
+def eptype(name, TYPE, ctypecls):
+ PRIMITIVE_TYPES[name] = ctypecls, rffi.sizeof(TYPE)
+
+eptype("char", lltype.Char, ctypeobj.W_CTypePrimitiveChar)
+eptype("signed char", rffi.SIGNEDCHAR, ctypeobj.W_CTypePrimitiveSigned)
+
+
+ at unwrap_spec(name=str)
+def new_primitive_type(space, name):
+ try:
+ ctypecls, size = PRIMITIVE_TYPES[name]
+ except KeyError:
+ raise OperationError(space.w_KeyError, space.wrap(name))
+ return ctypecls(space, name, size)
diff --git a/pypy/module/_ffi_backend/test/test_c.py b/pypy/module/_ffi_backend/test/test_c.py
--- a/pypy/module/_ffi_backend/test/test_c.py
+++ b/pypy/module/_ffi_backend/test/test_c.py
@@ -43,24 +43,24 @@
assert d['size_t'] == d['ssize_t'] + 0x1000
def test_new_primitive_type(self):
- py.test.raises(KeyError, new_primitive_type, "foo")
- p = new_primitive_type("signed char")
+ raises(KeyError, self.b.new_primitive_type, "foo")
+ p = self.b.new_primitive_type("signed char")
assert repr(p) == "<ctype 'signed char'>"
def test_cast_to_signed_char(self):
- p = new_primitive_type("signed char")
- x = cast(p, -65 + 17*256)
+ p = self.b.new_primitive_type("signed char")
+ x = self.b.cast(p, -65 + 17*256)
assert repr(x) == "<cdata 'signed char'>"
assert repr(type(x)) == "<type '_ffi_backend.CData'>"
assert int(x) == -65
- x = cast(p, -66 + (1<<199)*256)
+ x = self.b.cast(p, -66 + (1<<199)*256)
assert repr(x) == "<cdata 'signed char'>"
assert int(x) == -66
- assert (x == cast(p, -66)) is False
- assert (x != cast(p, -66)) is True
- q = new_primitive_type("short")
- assert (x == cast(q, -66)) is False
- assert (x != cast(q, -66)) is True
+ assert (x == self.b.cast(p, -66)) is False
+ assert (x != self.b.cast(p, -66)) is True
+ q = self.b.new_primitive_type("short")
+ assert (x == self.b.cast(q, -66)) is False
+ assert (x != self.b.cast(q, -66)) is True
def test_sizeof_type(self):
py.test.raises(TypeError, sizeof, 42.5)
More information about the pypy-commit
mailing list