Author: Armin Rigo <[email protected]>
Branch: static-callback
Changeset: r2414:40fdfeb33597
Date: 2015-11-18 09:28 +0100
http://bitbucket.org/cffi/cffi/changeset/40fdfeb33597/

Log:    Fix cparser

diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -54,7 +54,7 @@
 OP_DLOPEN_FUNC     = 35
 OP_DLOPEN_CONST    = 37
 OP_GLOBAL_VAR_F    = 39
-OP_CALL_PYTHON     = 41
+OP_EXTERN_PYTHON   = 41
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -29,7 +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_extern_python = re.compile(r'\bextern\s*"Python"\s*.')
 _r_star_const_space = re.compile(       # matches "* const "
     r"[*]\s*((const|volatile|restrict)\b\s*)+")
 
@@ -81,6 +81,47 @@
     parts.append(csource)
     return ''.join(parts)
 
+def _preprocess_extern_python(csource):
+    # input: `extern "Python" int foo(int);` or
+    #        `extern "Python" { int foo(int); }`
+    # output:
+    #     void __cffi_extern_python_start;
+    #     int foo(int);
+    #     void __cffi_extern_python_stop;
+    parts = []
+    while True:
+        match = _r_extern_python.search(csource)
+        if not match:
+            break
+        endpos = match.end() - 1
+        #print
+        #print ''.join(parts)+csource
+        #print '=>'
+        parts.append(csource[:match.start()])
+        parts.append('void __cffi_extern_python_start; ')
+        if csource[endpos] == '{':
+            # grouping variant
+            closing = csource.find('}', endpos)
+            if closing < 0:
+                raise api.CDefError("'extern \"Python\" {': no '}' found")
+            if csource.find('{', endpos + 1, closing) >= 0:
+                raise NotImplementedError("cannot use { } inside a block "
+                                          "'extern \"Python\" { ... }'")
+            parts.append(csource[endpos+1:closing])
+            csource = csource[closing+1:]
+        else:
+            # non-grouping variant
+            semicolon = csource.find(';', endpos)
+            if semicolon < 0:
+                raise api.CDefError("'extern \"Python\": no ';' found")
+            parts.append(csource[endpos:semicolon+1])
+            csource = csource[semicolon+1:]
+        parts.append(' void __cffi_extern_python_stop;')
+        #print ''.join(parts)+csource
+        #print
+    parts.append(csource)
+    return ''.join(parts)
+
 def _preprocess(csource):
     # Remove comments.  NOTE: this only work because the cdef() section
     # should not contain any string literal!
@@ -105,8 +146,8 @@
     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 `extern "Python"` with start/end markers
+    csource = _preprocess_extern_python(csource)
     #
     # Replace "[...]" with "[__dotdotdotarray__]"
     csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
@@ -263,9 +304,8 @@
                 break
         #
         try:
-            self._found_cffi_call_python = False
+            self._inside_extern_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):
@@ -288,8 +328,6 @@
                     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:
@@ -338,9 +376,8 @@
 
     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
+        if self._inside_extern_python:
+            self._declare('extern_python ' + decl.name, tp)
         else:
             self._declare('function ' + decl.name, tp)
 
@@ -378,15 +415,23 @@
                         _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)
+                elif (tp is model.void_type and
+                      decl.name.startswith('__cffi_extern_python_')):
+                    # hack: `extern "Python"` in the C source is replaced
+                    # with "void __cffi_extern_python_start;" and
+                    # "void __cffi_extern_python_stop;"
+                    self._inside_extern_python = not self._inside_extern_python
+                    assert self._inside_extern_python == (
+                        decl.name == '__cffi_extern_python_start')
                 else:
-                    self._declare('variable ' + decl.name, tp, quals=quals)
+                    if self._inside_extern_python:
+                        raise api.CDefError(
+                            "cannot declare constants or "
+                            "variables with 'extern \"Python\"'")
+                    if (quals & model.Q_CONST) and not tp.is_array_type:
+                        self._declare('constant ' + decl.name, tp, quals=quals)
+                    else:
+                        self._declare('variable ' + decl.name, tp, quals=quals)
 
     def parse_type(self, cdecl):
         return self.parse_type_and_quals(cdecl)[0]
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
@@ -406,16 +406,30 @@
                         "long(*)(), "
                         "short(%s*)(short))'>" % (stdcall, stdcall))
 
-def test_CFFI_CALL_PYTHON():
+def test_extern_python():
     ffi = FFI()
     ffi.cdef("""
+        int bok(int, int);
+        extern "Python" int foobar(int, int);
         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 sorted(ffi._parser._declarations) == [
+        'extern_python foobar', 'function baz', 'function bok']
+    assert (ffi._parser._declarations['function bok'] ==
+            ffi._parser._declarations['extern_python foobar'] ==
+            ffi._parser._declarations['function baz'])
+
+def test_extern_python_group():
+    ffi = FFI()
+    ffi.cdef("""
+        int bok(int);
+        extern "Python" {int foobar(int, int);int bzrrr(int);}
+        int baz(int, int);
+    """)
+    assert sorted(ffi._parser._declarations) == [
+        'extern_python bzrrr', 'extern_python foobar',
+        'function baz', 'function bok']
     assert (ffi._parser._declarations['function baz'] ==
-            ffi._parser._declarations['call_python foobar'])
+            ffi._parser._declarations['extern_python foobar'] !=
+            ffi._parser._declarations['function bok'] ==
+            ffi._parser._declarations['extern_python bzrrr'])
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to