[pypy-commit] cffi auto-types: Implementation

arigo noreply at buildbot.pypy.org
Sun Feb 10 19:09:51 CET 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: auto-types
Changeset: r1142:ee2c2a732000
Date: 2013-02-10 18:52 +0100
http://bitbucket.org/cffi/cffi/changeset/ee2c2a732000/

Log:	Implementation

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3214,7 +3214,7 @@
         return NULL;
 
     flag = CT_STRUCT;
-    if (strcmp(name, "_IO_FILE") == 0)
+    if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
         flag |= CT_IS_FILE;
     return _b_struct_or_union_type("struct", name, flag);
 }
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2505,7 +2505,7 @@
     if sys.platform == "win32":
         py.test.skip("testing FILE not implemented")
     #
-    BFILE = new_struct_type("_IO_FILE")
+    BFILE = new_struct_type("$FILE")
     BFILEP = new_pointer_type(BFILE)
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -71,7 +71,6 @@
             if name.startswith('RTLD_'):
                 setattr(self, name, getattr(backend, name))
         #
-        self._parser._declarations['typedef FILE'] = model.file_type
         BVoidP = self._get_cached_btype(model.voidp_type)
         if isinstance(backend, types.ModuleType):
             # _cffi_backend: attach these constants to the class
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -1,5 +1,6 @@
 
 from . import api, model
+from .commontypes import COMMON_TYPES
 import pycparser.c_parser, weakref, re, sys
 
 try:
@@ -17,6 +18,7 @@
 _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
 _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
 _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
+_r_words = re.compile(r"\w+|\S")
 _parser_cache = None
 
 def _get_parser():
@@ -58,10 +60,34 @@
     # which is declared with a typedef for the purpose of C parsing.
     return csource.replace('...', ' __dotdotdot__ '), macros
 
+def _common_type_names(csource):
+    # Look in the source for what looks like usages of types from the
+    # list of common types.  A "usage" is approximated here as the
+    # appearance of the word, minus a "definition" of the type, which
+    # is the last word in a "typedef" statement.  Approximative only
+    # but should be fine for all the common types.
+    look_for_words = set(COMMON_TYPES)
+    look_for_words.add(';')
+    look_for_words.add('typedef')
+    words_used = set()
+    is_typedef = False
+    previous_word = ''
+    for word in _r_words.findall(csource):
+        if word in look_for_words:
+            if word == ';':
+                if is_typedef:
+                    words_used.discard(previous_word)
+                    look_for_words.discard(previous_word)
+                    is_typedef = False
+            elif word == 'typedef':
+                is_typedef = True
+            else:   # word in COMMON_TYPES
+                words_used.add(word)
+        previous_word = word
+    return words_used
+
+
 class Parser(object):
-    TYPEDEFS = sorted(
-        [_name for _name in model.PrimitiveType.ALL_PRIMITIVE_TYPES
-               if _name.endswith('_t')])
 
     def __init__(self):
         self._declarations = {}
@@ -70,17 +96,23 @@
         self._override = False
 
     def _parse(self, csource):
+        csource, macros = _preprocess(csource)
         # XXX: for more efficiency we would need to poke into the
         # internals of CParser...  the following registers the
         # typedefs, because their presence or absence influences the
         # parsing itself (but what they are typedef'ed to plays no role)
-        typenames = self.TYPEDEFS[:]
+        ctn = _common_type_names(csource)
+        print `csource`, ctn
+        typenames = []
         for name in sorted(self._declarations):
             if name.startswith('typedef '):
-                typenames.append(name[8:])
+                name = name[8:]
+                typenames.append(name)
+                ctn.discard(name)
+        typenames += sorted(ctn)
+        #
         csourcelines = ['typedef int %s;' % typename for typename in typenames]
         csourcelines.append('typedef int __dotdotdot__;')
-        csource, macros = _preprocess(csource)
         csourcelines.append(csource)
         csource = '\n'.join(csourcelines)
         if lock is not None:
@@ -267,6 +299,8 @@
                     return model.void_type
                 if ident == '__dotdotdot__':
                     raise api.FFIError('bad usage of "..."')
+                if ident in COMMON_TYPES:
+                    return COMMON_TYPES[ident]
                 return model.PrimitiveType(ident)
             #
             if isinstance(type, pycparser.c_ast.Struct):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -73,9 +73,9 @@
         'float':              'f',
         'double':             'f',
         'long double':        'f',
-        'wchar_t':            'c',
         '_Bool':              'u',
         # the following types are not primitive in the C sense
+        'wchar_t':            'c',
         'int8_t':             'i',
         'uint8_t':            'u',
         'int16_t':            'i',
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -208,3 +208,10 @@
     assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
     e = py.test.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
     assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')
+
+def test_redefine_common_type():
+    ffi = FFI()
+    ffi.cdef("typedef char FILE;")
+    assert repr(ffi.cast("FILE", 123)) == "<cdata 'char' '{'>"
+    ffi.cdef("typedef char int32_t;")
+    assert repr(ffi.cast("int32_t", 123)) == "<cdata 'char' '{'>"


More information about the pypy-commit mailing list