[pypy-commit] cffi static-callback: Parsing CFFI_CALL_PYTHON in the cdef

arigo noreply at buildbot.pypy.org
Thu Nov 12 10:39:10 EST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: static-callback
Changeset: r2379:162bd2e749a1
Date: 2015-11-12 16:39 +0100
http://bitbucket.org/cffi/cffi/changeset/162bd2e749a1/

Log:	Parsing CFFI_CALL_PYTHON in the cdef

diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -29,6 +29,7 @@
 _r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
 _r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
 _r_cdecl = re.compile(r"\b__cdecl\b")
+_r_cffi_call_python = re.compile(r"\bCFFI_CALL_PYTHON\b")
 _r_star_const_space = re.compile(       # matches "* const "
     r"[*]\s*((const|volatile|restrict)\b\s*)+")
 
@@ -101,8 +102,13 @@
     csource = _r_stdcall2.sub(' volatile volatile const(', csource)
     csource = _r_stdcall1.sub(' volatile volatile const ', csource)
     csource = _r_cdecl.sub(' ', csource)
+    #
+    # Replace "CFFI_CALL_PYTHON" with "void CFFI_CALL_PYTHON;"
+    csource = _r_cffi_call_python.sub('void CFFI_CALL_PYTHON;', csource)
+    #
     # Replace "[...]" with "[__dotdotdotarray__]"
     csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
+    #
     # Replace "...}" with "__dotdotdotNUM__}".  This construction should
     # occur only at the end of enums; at the end of structs we have "...;}"
     # and at the end of vararg functions "...);".  Also replace "=...[,}]"
@@ -255,7 +261,9 @@
                 break
         #
         try:
+            self._found_cffi_call_python = False
             for decl in iterator:
+                old_cffi_call_python = self._found_cffi_call_python
                 if isinstance(decl, pycparser.c_ast.Decl):
                     self._parse_decl(decl)
                 elif isinstance(decl, pycparser.c_ast.Typedef):
@@ -278,6 +286,8 @@
                     self._declare('typedef ' + decl.name, realtype, quals=quals)
                 else:
                     raise api.CDefError("unrecognized construct", decl)
+                if old_cffi_call_python and self._found_cffi_call_python:
+                    raise api.CDefError("CFFI_CALL_PYTHON misplaced")
         except api.FFIError as e:
             msg = self._convert_pycparser_error(e, csource)
             if msg:
@@ -324,13 +334,20 @@
                     '  #define %s %s'
                     % (key, key, key, value))
 
+    def _declare_function(self, tp, quals, decl):
+        tp = self._get_type_pointer(tp, quals)
+        if self._found_cffi_call_python:
+            self._declare('call_python ' + decl.name, tp)
+            self._found_cffi_call_python = False
+        else:
+            self._declare('function ' + decl.name, tp)
+
     def _parse_decl(self, decl):
         node = decl.type
         if isinstance(node, pycparser.c_ast.FuncDecl):
             tp, quals = self._get_type_and_quals(node, name=decl.name)
             assert isinstance(tp, model.RawFunctionType)
-            tp = self._get_type_pointer(tp, quals)
-            self._declare('function ' + decl.name, tp)
+            self._declare_function(tp, quals, decl)
         else:
             if isinstance(node, pycparser.c_ast.Struct):
                 self._get_struct_union_enum_type('struct', node)
@@ -346,8 +363,7 @@
                 tp, quals = self._get_type_and_quals(node,
                                                      partial_length_ok=True)
                 if tp.is_raw_function:
-                    tp = self._get_type_pointer(tp, quals)
-                    self._declare('function ' + decl.name, tp)
+                    self._declare_function(tp, quals, decl)
                 elif (tp.is_integer_type() and
                         hasattr(decl, 'init') and
                         hasattr(decl.init, 'value') and
@@ -360,6 +376,11 @@
                         _r_int_literal.match(decl.init.expr.value)):
                     self._add_integer_constant(decl.name,
                                                '-' + decl.init.expr.value)
+                elif tp is model.void_type and decl.name == 'CFFI_CALL_PYTHON':
+                    # hack: "CFFI_CALL_PYTHON" in the C source is replaced
+                    # with "void CFFI_CALL_PYTHON;", which when parsed arrives
+                    # at this point and sets this flag:
+                    self._found_cffi_call_python = True
                 elif (quals & model.Q_CONST) and not tp.is_array_type:
                     self._declare('constant ' + decl.name, tp, quals=quals)
                 else:
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -405,3 +405,17 @@
         "<ctype 'int(*)(int(%s*)(int), "
                         "long(*)(), "
                         "short(%s*)(short))'>" % (stdcall, stdcall))
+
+def test_CFFI_CALL_PYTHON():
+    ffi = FFI()
+    ffi.cdef("""
+        int baz(int, int);
+        CFFI_CALL_PYTHON int foobar(int, int);
+    """)
+    assert 'variable CFFI_CALL_PYTHON' not in ffi._parser._declarations
+    assert 'function baz' in ffi._parser._declarations
+    assert 'call_python baz' not in ffi._parser._declarations
+    assert 'function foobar' not in ffi._parser._declarations
+    assert 'call_python foobar' in ffi._parser._declarations
+    assert (ffi._parser._declarations['function baz'] ==
+            ffi._parser._declarations['call_python foobar'])


More information about the pypy-commit mailing list