Commits

Armin Rigo committed 6b77c57

Floats.

  • Participants
  • Parent commits 515c235

Comments (0)

Files changed (4)

             return self._backend.get_cached_btype('new_array_type',
                                                   BItem, length)
         #
-        elif isinstance(typenode, pycparser.c_ast.TypeDecl):
-            # assume a primitive type
-            names = typenode.type.names
-            if len(names) > 1 and names[-1] == 'int':
-                names = names[:-1]
-            ident = ' '.join(names)
-            return self._backend.get_cached_btype('new_primitive_type', ident)
-        #
-        elif isinstance(typenode, pycparser.c_ast.PtrDecl):
+        if isinstance(typenode, pycparser.c_ast.PtrDecl):
             BItem = self._get_btype(typenode.type)
             return self._backend.get_cached_btype("new_pointer_type", BItem)
         #
-        else:
-            raise FFIError("bad or unsupported type declaration")
+        if isinstance(typenode, pycparser.c_ast.TypeDecl):
+            type = typenode.type
+            if isinstance(type, pycparser.c_ast.IdentifierType):
+                # assume a primitive type.  get it from .names, but reduce
+                # synonyms to a single chosen combination
+                names = list(type.names)
+                if names == ['signed'] or names == ['unsigned']:
+                    names.append('int')
+                if names[0] == 'signed' and names != ['signed', 'char']:
+                    names.pop(0)
+                if (len(names) > 1 and names[-1] == 'int'
+                        and names != ['unsigned', 'int']):
+                    names.pop()
+                ident = ' '.join(names)
+                return self._backend.get_cached_btype(
+                    'new_primitive_type', ident)
+            #
+            if isinstance(type, pycparser.c_ast.Struct):
+                xxx
+        #
+        raise FFIError("bad or unsupported type declaration")
 
 
 class FFILibrary(object):
         if name in self.ffi._functions:
             raise FFIError("multiple declaration of function %r" % (name,))
         self.ffi._functions[name] = node
+
+    def visit_Struct(self, node):
+        xxx

File ffi/backend_ctypes.py

         'long': ctypes.c_long,
         'long long': ctypes.c_longlong,
         'signed char': ctypes.c_byte,
-        'signed short': ctypes.c_short,
-        'signed': ctypes.c_int,
-        'signed long': ctypes.c_long,
-        'signed long long': ctypes.c_longlong,
         'unsigned char': ctypes.c_ubyte,
         'unsigned short': ctypes.c_ushort,
-        'unsigned': ctypes.c_uint,
+        'unsigned int': ctypes.c_uint,
         'unsigned long': ctypes.c_ulong,
         'unsigned long long': ctypes.c_ulonglong,
+        'float': ctypes.c_float,
         'double': ctypes.c_double,
     }
 
     def new_primitive_type(self, name):
         ctype = self.PRIMITIVE_TYPES[name]
         if name == 'char':
-            pass
+            kind = 'char'
+            default_value = '\x00'
+        elif name in ('float', 'double'):
+            kind = 'float'
+            default_value = 0.0
         else:
-            # integer types
+            kind = 'int'
+            default_value = 0
             is_signed = (ctype(-1).value == -1)
         #
-        class CTypesInt(CTypesData):
+        class CTypesPrimitive(CTypesData):
             _ctype = ctype
             _reftypename = '%s &' % name
 
             def __init__(self, value):
                 if value is None:
-                    if name == 'char':
-                        value = '\x00'
-                    else:
-                        value = 0
-                elif ctype(value).value != value:
-                    raise OverflowError("%r out of range: %d" %
-                                        (name, value))
+                    value = default_value
+                else:
+                    value = CTypesPrimitive._to_ctypes(value)
                 self._value = value
 
-            def __int__(self):
-                if name == 'char':
+            if kind == 'int':
+                def __int__(self):
+                    return self._value
+
+            if kind == 'char':
+                def __int__(self):
                     return ord(self._value)
-                return self._value
+                __nonzero__ = __int__
+            else:
+                def __nonzero__(self):
+                    return bool(self._value)
 
-            __nonzero__ = __int__
+            if kind == 'float':
+                def __int__(self):
+                    return int(self._value)
+                def __float__(self):
+                    return self._value
 
             def __eq__(self, other): return self._value == other
             def __ne__(self, other): return self._value != other
             def __gt__(self, other): raise TypeError("unorderable type")
             def __ge__(self, other): raise TypeError("unorderable type")
 
-            @staticmethod
-            def _to_ctypes(x):
-                if name == 'char':
+            if kind == 'int':
+                @staticmethod
+                def _to_ctypes(x):
+                    if not isinstance(x, (int, long)):
+                        if isinstance(x, CTypesData):
+                            x = int(x)
+                        else:
+                            raise TypeError("integer expected, got %s" %
+                                            type(x).__name__)
+                    if ctype(x).value != x:
+                        if not is_signed and x < 0:
+                            raise OverflowError("%s: negative integer" % name)
+                        else:
+                            raise OverflowError("%s: integer out of bounds"
+                                                % name)
+                    return x
+
+            if kind == 'char':
+                @staticmethod
+                def _to_ctypes(x):
                     if isinstance(x, str) and len(x) == 1:
                         return x
-                    if isinstance(x, CTypesInt):    # <CData <char>>
+                    if isinstance(x, CTypesPrimitive):    # <CData <char>>
                         return x._value
                     raise TypeError("character expected, got %s" %
                                     type(x).__name__)
-                #
-                if not isinstance(x, (int, long)):
-                    if isinstance(x, CTypesData):
-                        x = int(x)
-                    else:
-                        raise TypeError("integer expected, got %s" %
+
+            if kind == 'float':
+                @staticmethod
+                def _to_ctypes(x):
+                    if not isinstance(x, (int, long, float, CTypesData)):
+                        raise TypeError("float expected, got %s" %
                                         type(x).__name__)
-                if ctype(x).value != x:
-                    if not is_signed and x < 0:
-                        raise OverflowError("%s: negative integer" % name)
-                    else:
-                        raise OverflowError("%s: integer out of bounds" % name)
-                return x
+                    return ctype(x).value
+
             _from_ctypes = staticmethod(_identity)
         #
-        CTypesInt._fix_class()
-        return CTypesInt
+        CTypesPrimitive._fix_class()
+        return CTypesPrimitive
 
     def new_pointer_type(self, BItem):
         #

File testing/backend_tests.py

         assert p[0] is None
         assert ffi.new("int*") == None
         assert ffi.new("int*") is not None
+
+    def test_float(self):
+        ffi = FFI(backend=self.Backend())
+        p = ffi.new("float[]", [-2, -2.5])
+        assert p[0] == -2.0
+        assert p[1] == -2.5
+        p[1] += 17.75
+        assert p[1] == 15.25
+        #
+        f = ffi.new("float", 15.75)
+        assert int(f) == 15 and type(int(f)) is int
+        assert float(f) == 15.75 and type(float(f)) is float
+        assert bool(f) is True
+        assert bool(ffi.new("float", 0.0)) is False
+        assert f == 15.75
+        assert f != 16.2
+        #
+        f = ffi.new("float", 1.1)
+        assert f != 1.1      # because of rounding effect
+        assert abs(float(f) - 1.1) < 1E-7
+        f = ffi.new("float", 1E200)
+        assert float(f) == 1E200 * 1E200     # infinite, not enough precision
+
+    def test_struct_simple(self):
+        py.test.skip("in-progress")
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("struct foo { int a; short b, c; };")
+        s = ffi.new("struct foo")
+        assert s.a == s.b == s.c == 0
+        s.b = -23
+        assert s.b == -23
+        py.test.raises(OverflowError, "s.b = 32768")

File testing/test_cdata.py

 
 def test_typeof():
     ffi = FFI(backend=FakeBackend())
-    clong = ffi.typeof("long")
+    clong = ffi.typeof("signed long int")
     assert isinstance(clong, FakePrimitiveType)
     assert clong.cdecl == 'long'