[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