[pypy-commit] pypy rffi-parser: Handle includes

rlamy pypy.commits at gmail.com
Sat Dec 17 10:25:05 EST 2016


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: rffi-parser
Changeset: r89116:078ef51e7af9
Date: 2016-12-17 15:24 +0000
http://bitbucket.org/pypy/pypy/changeset/078ef51e7af9/

Log:	Handle includes

diff --git a/pypy/module/cpyext/cparser.py b/pypy/module/cpyext/cparser.py
--- a/pypy/module/cpyext/cparser.py
+++ b/pypy/module/cpyext/cparser.py
@@ -26,12 +26,11 @@
         _parser_cache = pycparser.CParser()
     return _parser_cache
 
-def _preprocess(csource):
+def _preprocess(csource, macros):
     # Remove comments.  NOTE: this only work because the cdef() section
     # should not contain any string literal!
     csource = _r_comment.sub(' ', csource)
     # Remove the "#define FOO x" lines
-    macros = OrderedDict()
     for match in _r_define.finditer(csource):
         macroname, macrovalue = match.groups()
         macrovalue = macrovalue.replace('\\\n', '').strip()
@@ -102,9 +101,11 @@
         self._options = {}
         self._int_constants = {}
         self._recomplete = []
+        self._macros = OrderedDict()
 
     def _parse(self, csource):
-        csource, macros = _preprocess(csource)
+        # modifies self._macros in-place
+        csource, macros = _preprocess(csource, self._macros)
         # 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
@@ -633,10 +634,12 @@
             if name.startswith('anonymous $enum_$'):
                 continue   # fix for test_anonymous_enum_include
             kind = name.split(' ', 1)[0]
-            if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
+            if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef', 'macro'):
                 self._declare(name, tp, included=True, quals=quals)
         for k, v in other._int_constants.items():
             self._add_constants(k, v)
+        for k, v in other._macros.items():
+            self._macros[k] = v
 
 CNAME_TO_LLTYPE = {
     'char': rffi.CHAR,
@@ -671,11 +674,12 @@
 
 
 class ParsedSource(object):
-    def __init__(self, source, definitions=None, macros=None):
+    def __init__(self, source, parser, definitions=None, macros=None):
         self.source = source
         self.definitions = definitions if definitions is not None else {}
         self.macros = macros if macros is not None else {}
         self.structs = {}
+        self.ctx = parser
 
     def add_typedef(self, name, obj):
         assert name not in self.definitions
@@ -711,11 +715,17 @@
             raise NotImplementedError
 
 
-def parse_source(source):
+def parse_source(source, includes=None):
     ctx = Parser()
+    if includes is not None:
+        for header in includes:
+            ctx.include(header.ctx)
+
     ctx.parse(source)
-    src = ParsedSource(source)
+    src = ParsedSource(source, ctx)
     for name, (obj, quals) in ctx._declarations.iteritems():
+        if obj in ctx._included_declarations:
+            continue
         if name.startswith('typedef '):
             name = name[8:]
             src.add_typedef(name, obj)
diff --git a/pypy/module/cpyext/test/test_cparser.py b/pypy/module/cpyext/test/test_cparser.py
--- a/pypy/module/cpyext/test/test_cparser.py
+++ b/pypy/module/cpyext/test/test_cparser.py
@@ -39,3 +39,21 @@
     hdr = parse_source(decl)
     assert 'PyFloatObject' in hdr.definitions
     assert 'PyObject_HEAD' in hdr.macros
+
+def test_include():
+    cdef1 = """
+    typedef ssize_t Py_ssize_t;
+
+    #define PyObject_HEAD  \
+        Py_ssize_t ob_refcnt;        \
+        Py_ssize_t ob_pypy_link;     \
+    """
+    hdr1 = parse_source(cdef1)
+    cdef2 = """
+    typedef struct {
+        PyObject_HEAD
+        Py_ssize_t ob_foo;
+    } Object;
+    """
+    hdr2 = parse_source(cdef2, includes=[hdr1])
+    assert 'Object' in hdr2.definitions


More information about the pypy-commit mailing list