[pypy-commit] creflect default: Pass struct-001

arigo noreply at buildbot.pypy.org
Tue Sep 16 11:32:55 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r43:183e7881542b
Date: 2014-09-16 11:33 +0200
http://bitbucket.org/cffi/creflect/changeset/183e7881542b/

Log:	Pass struct-001

diff --git a/creflect/cparser.py b/creflect/cparser.py
--- a/creflect/cparser.py
+++ b/creflect/cparser.py
@@ -54,8 +54,7 @@
     def __init__(self, cdefblock, first_lineno=1):
         self.cdefblock = cdefblock
         self.first_lineno = first_lineno
-        self._structnode2type = {}
-        self._structunionenum = {}
+        self._struct_union_enum_decl = {}
 
     def to_ast(self):
         cparser = pycparser.CParser()
@@ -99,16 +98,16 @@
             tp = self._get_type_pointer(tp)
             self._declare('function ' + decl.name, tp)
         else:
+            const = 'const' in decl.quals
             if isinstance(node, pycparser.c_ast.Struct):
-                # XXX do we need self._declare in any of those?
                 if node.decls is not None:
-                    self._get_struct_union_enum_type('struct', node)
+                    self._get_struct_union_enum_type('struct', node, const)
             elif isinstance(node, pycparser.c_ast.Union):
                 if node.decls is not None:
-                    self._get_struct_union_enum_type('union', node)
+                    self._get_struct_union_enum_type('union', node, const)
             elif isinstance(node, pycparser.c_ast.Enum):
                 if node.values is not None:
-                    self._get_struct_union_enum_type('enum', node)
+                    self._get_struct_union_enum_type('enum', node, const)
             elif not decl.name:
                 raise api.CDefError("construct does not declare any variable",
                                     decl)
@@ -199,87 +198,38 @@
         raise api.FFIError(":%d: bad or unsupported type declaration" %
                 typenode.coord.line)
 
-    def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
-        # First, a level of caching on the exact 'type' node of the AST.
-        # This is obscure, but needed because pycparser "unrolls" declarations
-        # such as "typedef struct { } foo_t, *foo_p" and we end up with
-        # an AST that is not a tree, but a DAG, with the "type" node of the
-        # two branches foo_t and foo_p of the trees being the same node.
-        # It's a bit silly but detecting "DAG-ness" in the AST tree seems
-        # to be the only way to distinguish this case from two independent
-        # structs.  See test_struct_with_two_usages.
-        try:
-            return self._structnode2type[type]
-        except KeyError:
-            pass
+    def _get_struct_union_enum_type(self, kind, type, const):
+        name = type.name
+        assert name   # XXX
+        result = model.StructOrUnionOrEnum(kind, name, const)
         #
-        # Note that this must handle parsing "struct foo" any number of
-        # times and always return the same StructType object.  Additionally,
-        # one of these times (not necessarily the first), the fields of
-        # the struct can be specified with "struct foo { ...fields... }".
-        # If no name is given, then we have to create a new anonymous struct
-        # with no caching; in this case, the fields are either specified
-        # right now or never.
+        # get the type declaration or create it if needed
+        key = '%s %s' % (kind, name)
+        typedecl = self._struct_union_enum_decl.get(key, None)
         #
-        force_name = name
-        name = type.name
-        #
-        # get the type or create it if needed
-        if name is None:
-            # 'force_name' is used to guess a more readable name for
-            # anonymous structs, for the common case "typedef struct { } foo".
-            if force_name is not None:
-                explicit_name = '$%s' % force_name
-            else:
-                self._anonymous_counter += 1
-                explicit_name = '$%d' % self._anonymous_counter
-            tp = None
-        else:
-            explicit_name = name
-            key = '%s %s' % (kind, name)
-            tp = self._structunionenum.get(key, None)
-        #
-        if tp is None:
-            if kind == 'struct':
-                tp = model.StructType(explicit_name, None, None, None)
-            elif kind == 'union':
-                tp = model.UnionType(explicit_name, None, None, None)
+        if typedecl is None:
+            if kind == 'struct' or kind == 'union':
+                typedecl = model.StructOrUnionDecl(result)
             elif kind == 'enum':
-                tp = self._build_enum_type(explicit_name, type.values)
+                typedecl = XXX
             else:
                 raise AssertionError("kind = %r" % (kind,))
-            if name is not None:
-                self._structunionenum[key] = tp
-                self.declarations.append(tp)
-        else:
-            if kind == 'enum' and type.values is not None:
-                raise NotImplementedError(
-                    "enum %s: the '{}' declaration should appear on the first "
-                    "time the enum is mentioned, not later" % explicit_name)
-        ## XXX
-        ## if not tp.forcename:
-        ##     tp.force_the_name(force_name)
-        ## if tp.forcename and '$' in tp.name:
-        ##     self._declare('anonymous %s' % tp.forcename, tp)
-        #
-        self._structnode2type[type] = tp
-        #
-        # enums: done here
-        if kind == 'enum':
-            return tp
+            self._struct_union_enum_decl[key] = typedecl
+            self.declarations.append(typedecl)
         #
         # is there a 'type.decls'?  If yes, then this is the place in the
-        # C sources that declare the fields.  If no, then just return the
-        # existing type, possibly still incomplete.
-        if type.decls is None:
-            return tp
-        #
-        if tp.fldnames is not None:
+        # C sources that declare the fields.
+        if type.decls is not None:
+            self._add_fields_declaration(typedecl, type.decls)
+        return result
+
+    def _add_fields_declaration(self, typedecl, fields):
+        if typedecl.fldnames is not None:
             raise api.CDefError("duplicate declaration of struct %s" % name)
         fldnames = []
         fldtypes = []
         fldbitsize = []
-        for decl in type.decls:
+        for decl in fields:
             if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
                     ''.join(decl.type.names) == '__dotdotdot__'):
                 # XXX pycparser is inconsistent: 'names' should be a list
@@ -295,19 +245,19 @@
             type = self._get_type(decl.type, partial_length_ok=True)
             if self._partial_length:
                 self._make_partial(tp, nested)
-            if isinstance(type, model.StructType) and type.partial:
-                self._make_partial(tp, nested)
+            #if isinstance(type, model.StructType) and type.partial:
+            #    self._make_partial(tp, nested)
             fldnames.append(decl.name or '')
             fldtypes.append(type)
             fldbitsize.append(bitsize)
-        tp.fldnames = tuple(fldnames)
-        tp.fldtypes = tuple(fldtypes)
-        tp.fldbitsize = tuple(fldbitsize)
+        typedecl.fldnames = tuple(fldnames)
+        typedecl.fldtypes = tuple(fldtypes)
+        typedecl.fldbitsize = tuple(fldbitsize)
         if fldbitsize != [-1] * len(fldbitsize):
+            xxxx
             if isinstance(tp, model.StructType) and tp.partial:
                 raise NotImplementedError("%s: using both bitfields and '...;'"
                                           % (tp,))
-        return tp
 
     def _parse_constant(self, *args, **kwds):
         return None     # XXX
diff --git a/creflect/model.py b/creflect/model.py
--- a/creflect/model.py
+++ b/creflect/model.py
@@ -326,7 +326,7 @@
                 line = '%sp1->%s = (void *)%s;%s%s' % (
                     '*' * (length - 1), self.structfield, expr, spaces, comment)
             else:
-                line = 'p1 = (void *)(((char *)%s) - (long)o);' % (expr,)
+                line = 'p1 = (void *)(((char *)%s) - o);' % (expr,)
         self.assign_target = None
         self.block.writeline(line.rstrip())
         for fn in self.after_star_p1_assignment:
@@ -343,46 +343,52 @@
 
 class StructOrUnionDecl(object):
 
-    def __init__(self, type, fldnames, fldtypes, fldbitsize):
+    def __init__(self, type):
         self.type = type
-        self.fldnames = fldnames
-        self.fldtypes = fldtypes
-        self.fldbitsize = fldbitsize
+        self.fldnames = None
+        self.fldtypes = None
+        self.fldbitsize = None
 
-    def write_declaration(self, tr):
-        tr.reset_r_output()
-        typename = "%s %s" % (self.kind, self.name)
-        tr.write_msg(typename)
-        tr.write_section("a[%d] = (void *)sizeof(%s);  /* size */"
-                          % (tr.fetch_next_a_index(), typename), indent=4)
-        tr.write_section("a[%d] = &((struct{char a; %s b;}*)0)->b;  /* align */"
-                          % (tr.fetch_next_a_index(), typename), indent=4)
-        tr.flush()
+    def write_declaration(self, funcblock):
+        tp = "%s %s" % (self.type.kind, self.type.name)
+        extra1 = "(long long)sizeof(%s)" % (tp,)    # total size
+        extra2 = ("(long long)(((char *)&((struct{char a; %s b;} *)0)->b)"
+                  " - (char *)0)" % (tp,))          # alignment
+        funcblock.sprintf(tp + r" {/*%lld,%lld*/\n",
+                          extra="%s, %s" % (extra1, extra2),
+                          extralength=40)
+        #
         for fldname, fldtype in zip(self.fldnames, self.fldtypes):
-            tr.reset_r_output()
-            tr.write_msg("{%s:" % (fldname,))
-            tr.fetch_next_a_index()   # ignored
-            outer = OuterDecl(tr, typename, fldname)
-            outer.start()
-            #
-            xtra = ''
+            block = CodeBlock(funcblock.tr)
+            inspect = TypeInspector(block, tp, fldname)
+            inspect.start()
+            # get the offset of the field
+            arraylevels = 0
             checktype = fldtype
             while isinstance(checktype, ArrayType):
-                xtra += '[0]'
+                arraylevels += 1
                 checktype = checktype.item
-            if xtra:
-                tr.add_include('stddef.h')
-                outer.decllines.append("void *o = (void *)offsetof(%s, %s%s);"
-                                       "  /* offset */" %
-                                       (typename, fldname, xtra))
+            if arraylevels:
+                block.add_include('stddef.h')
+                comment = ""
+                if arraylevels >= 1:
+                    comment = " (%dx)" % arraylevels
+                comment = inspect.get_comment(0, False, "an array%s" % comment)
+                block.writedecl("long long o = offsetof(%s, %s%s);%s"
+                                % (tp, fldname, "[0]" * arraylevels, comment))
             else:
-                outer.decllines.append("void *o = &((%s *)0)->%s;  /* offset */"
-                                       % (typename, fldname))
-            outer.codelines.append("a[%d] = o;" % (tr.fetch_next_a_index(),))
-            typeexpr = fldtype.outer_decl(outer)
-            outer.stop()
-            tr.write_msg(typeexpr.replace('&', ''))
-            tr.flush()
+                comment = inspect.get_comment(0, False, "not an array")
+                block.writedecl("long long o = ((char *)&((%s *)0)->%s)"
+                                " - (char *)0;%s" % (tp, fldname, comment))
+            #
+            block.sprintf("  /*%lld*/", extra="o", extralength=20)
+            block.sprintf_add_right(r';\n')
+            fldtype.inspect_type(block, inspect)
+            inspect.stop()
+            block.sprintf_add_left(fldname)
+            funcblock.write_subblock(block)
+        #
+        funcblock.sprintf(r"};\n")
 
 
 class TypeDef(object):
diff --git a/test/codegen/struct-001.c b/test/codegen/struct-001.c
--- a/test/codegen/struct-001.c
+++ b/test/codegen/struct-001.c
@@ -8,15 +8,15 @@
 int teststruct_001(char *r)
 {
     if (!r)
-        return 57 + 8 + 18 + 16;
+        return 69 + 30 + 18 + 6 + 30 + 18 + 6 + 4;
     r += sprintf(r, "struct foo_s {/*%lld,%lld*/\n", (long long)sizeof(struct foo_s), (long long)(((char *)&((struct{char a; struct foo_s b;} *)0)->b) - (char *)0));
     {
+        struct foo_s *p1;
         long long o = ((char *)&((struct foo_s *)0)->aa) - (char *)0;  /* check that 'struct foo_s::aa' is not an array */
-        struct foo_s *p1;
         char b[sizeof(p1->aa)];
+        r += sprintf(r, "  /*%lld*/", o);
         p1 = (void *)(((char *)b) - o);
         (void)(p1->aa << 1);  /* check that 'struct foo_s::aa' is an integer type */
-        r += sprintf(r, "  /*%lld*/", o);
         p1->aa = -1;  /* check that 'struct foo_s::aa' is not declared 'const' */
         if (p1->aa > 0) {
             if (sizeof(p1->aa) == 1 && p1->aa == 1)
@@ -51,12 +51,12 @@
         r += sprintf(r, " aa;\n");
     }
     {
+        struct foo_s *p1;
         long long o = ((char *)&((struct foo_s *)0)->bb) - (char *)0;  /* check that 'struct foo_s::bb' is not an array */
-        struct foo_s *p1;
         char b[sizeof(p1->bb)];
+        r += sprintf(r, "  /*%lld*/", o);
         p1 = (void *)(((char *)b) - o);
         (void)(p1->bb << 1);  /* check that 'struct foo_s::bb' is an integer type */
-        r += sprintf(r, "  /*%lld*/", o);
         p1->bb = -1;  /* check that 'struct foo_s::bb' is not declared 'const' */
         if (p1->bb > 0) {
             if (sizeof(p1->bb) == 1 && p1->bb == 1)


More information about the pypy-commit mailing list