[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