[pypy-commit] cffi cffi-1.0: Structs
arigo
noreply at buildbot.pypy.org
Sat May 16 09:08:31 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r2001:e0693e987861
Date: 2015-05-16 09:01 +0200
http://bitbucket.org/cffi/cffi/changeset/e0693e987861/
Log: Structs
diff --git a/c/cdlopen.c b/c/cdlopen.c
--- a/c/cdlopen.c
+++ b/c/cdlopen.c
@@ -271,7 +271,12 @@
describing one field each */
nfields[nf].field_type_op = cdl_opcode(f); f += 4;
nfields[nf].field_offset = (size_t)-1;
- nfields[nf].field_size = cdl_4bytes(f); f += 4;
+ if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) {
+ nfields[nf].field_size = cdl_4bytes(f); f += 4;
+ }
+ else {
+ nfields[nf].field_size = (size_t)-1;
+ }
nfields[nf].name = f;
nf++;
}
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -11,7 +11,7 @@
classname = CLASS_NAME[self.op]
return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg)
- def as_bytes(self):
+ def as_python_bytes(self):
assert self.op is not None
return format_four_bytes((self.arg << 8) | self.op)
@@ -153,6 +153,10 @@
F_EXTERNAL = 0x08
F_OPAQUE = 0x10
+G_FLAGS = dict([('_CFFI_' + _key, globals()[_key])
+ for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED',
+ 'F_EXTERNAL', 'F_OPAQUE']])
+
CLASS_NAME = {}
for _name, _value in list(globals().items()):
if _name.startswith('OP_') and isinstance(_value, int):
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -26,19 +26,65 @@
"ffi.dlopen() will not be able to figure out the value of "
"constant %r (only integer constants are supported, and only "
"if their value are specified in the cdef)" % (self.name,))
- return "b'%s%s',%d" % (self.type_op.as_bytes(), self.name,
+ return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
self.check_value)
-class TypenameExpr:
- def __init__(self, name, type_index):
+class FieldExpr:
+ def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
+ self.name = name
+ self.field_offset = field_offset
+ self.field_size = field_size
+ self.fbitsize = fbitsize
+ self.field_type_op = field_type_op
+
+ def as_c_expr(self):
+ return (' { "%s", %s,\n' % (fldname, offset) +
+ ' %s %s,\n' % (spaces, size) +
+ ' %s _CFFI_OP(%s, %s) },' % (
+ spaces, op, self._typesdict[fldtype]))
+
+ def as_python_expr(self):
+ raise NotImplementedError
+
+ def as_field_python_expr(self):
+ if self.field_type_op.op == OP_NOOP:
+ size_expr = ''
+ elif self.field_type_op.op == OP_BITFIELD:
+ size_expr = format_four_bytes(self.fbitsize)
+ else:
+ raise NotImplementedError
+ return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
+ size_expr,
+ self.name)
+
+class StructUnionExpr:
+ def __init__(self, name, type_index, flags, size, alignment, comment,
+ first_field_index, c_fields):
self.name = name
self.type_index = type_index
+ self.flags = flags
+ self.size = size
+ self.alignment = alignment
+ self.comment = comment
+ self.first_field_index = first_field_index
+ self.c_fields = c_fields
def as_c_expr(self):
- return ' { "%s", %d },' % (self.name, self.type_index)
+ return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
+ + '\n %s, %s, ' % (self.size, self.alignment)
+ + '%d, %d ' % (self.first_field_index, len(self.c_fields))
+ + ('/* %s */ ' % self.comment if self.comment else '')
+ + '}')
def as_python_expr(self):
- return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
+ flags = eval(self.flags, G_FLAGS)
+ fields_expr = [c_field.as_field_python_expr()
+ for c_field in self.c_fields]
+ return "(b'%s%s%s',%s)" % (
+ format_four_bytes(self.type_index),
+ format_four_bytes(flags),
+ self.name,
+ ','.join(fields_expr))
class EnumExpr:
def __init__(self, name, type_index, size, signed, allenums):
@@ -64,6 +110,20 @@
format_four_bytes(prim_index),
self.name, self.allenums)
+class TypenameExpr:
+ def __init__(self, name, type_index):
+ self.name = name
+ self.type_index = type_index
+
+ def as_c_expr(self):
+ return ' { "%s", %d },' % (self.name, self.type_index)
+
+ def as_python_expr(self):
+ return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
+
+
+# ____________________________________________________________
+
class Recompiler:
@@ -182,7 +242,8 @@
#
for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
- lst.sort(key=lambda entry: entry.name)
+ if step_name != "field":
+ lst.sort(key=lambda entry: entry.name)
self._lsts[step_name] = tuple(lst) # don't change any more
#
# check for a possible internal inconsistency: _cffi_struct_unions
@@ -190,7 +251,7 @@
lst = self._lsts["struct_union"]
for tp, i in self._struct_unions.items():
assert i < len(lst)
- assert lst[i].startswith(' { "%s"' % tp.name)
+ assert lst[i].name == tp.name
assert len(lst) == len(self._struct_unions)
# same with enums
lst = self._lsts["enum"]
@@ -262,9 +323,6 @@
if nums[step_name] > 0:
prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
step_name, step_name))
- if step_name == 'field':
- XXXX
- lst = list(self._fix_final_field_list(lst))
for entry in lst:
prnt(entry.as_c_expr())
prnt('};')
@@ -364,13 +422,13 @@
#
# the '_types' keyword argument
self.cffi_types = tuple(self.cffi_types) # don't change any more
- types_lst = [op.as_bytes() for op in self.cffi_types]
+ types_lst = [op.as_python_bytes() for op in self.cffi_types]
prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
#
for step_name in self.ALL_STEPS:
lst = self._lsts[step_name]
- if len(lst) > 0:
+ if len(lst) > 0 and step_name != "field":
prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
#
# the footer
@@ -692,16 +750,16 @@
flags.append("_CFFI_F_EXTERNAL")
reason_for_not_expanding = "external"
flags = '|'.join(flags) or '0'
+ c_fields = []
if reason_for_not_expanding is None:
- c_field = [approxname]
enumfields = list(tp.enumfields())
for fldname, fldtype, fbitsize in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
spaces = " " * len(fldname)
# cname is None for _add_missing_struct_unions() only
- op = '_CFFI_OP_NOOP'
+ op = OP_NOOP
if fbitsize >= 0:
- op = '_CFFI_OP_BITFIELD'
+ op = OP_BITFIELD
size = '%d /* bits */' % fbitsize
elif cname is None or (
isinstance(fldtype, model.ArrayType) and
@@ -719,34 +777,40 @@
named_ptr.name, fldname)
else:
offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
- c_field.append(
- ' { "%s", %s,\n' % (fldname, offset) +
- ' %s %s,\n' % (spaces, size) +
- ' %s _CFFI_OP(%s, %s) },' % (
- spaces, op, self._typesdict[fldtype]))
- self._lsts["field"].append('\n'.join(c_field))
+ c_fields.append(
+ FieldExpr(fldname, offset, size, fbitsize,
+ CffiOp(op, self._typesdict[fldtype])))
+ first_field_index = len(self._lsts["field"])
+ self._lsts["field"].extend(c_fields)
#
if cname is None: # unknown name, for _add_missing_struct_unions
- size_align = (' (size_t)-2, -2, /* unnamed */\n' +
- ' _cffi_FIELDS_FOR_%s, %d },' % (approxname,
- len(enumfields),))
+ #size_align = (' (size_t)-2, -2, /* unnamed */\n' +
+ # ' _cffi_FIELDS_FOR_%s, %d },' % (approxname,
+ # len(enumfields),))
+ size = -2
+ align = -2
+ comment = "unnamed"
else:
if named_ptr is not None:
size = 'sizeof(*(%s)0)' % (named_ptr.name,)
- align = '-1 /* unknown alignment */'
+ align = '-1 /* unknown alignment */'
else:
size = 'sizeof(%s)' % (cname,)
align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
- size_align = ('\n' +
- ' %s,\n' % (size,) +
- ' %s,\n' % (align,) +
- ' _cffi_FIELDS_FOR_%s, %d },' % (approxname,
- len(enumfields),))
+ #size_align = ('\n' +
+ # ' %s,\n' % (size,) +
+ # ' %s,\n' % (align,) +
+ # ' _cffi_FIELDS_FOR_%s, %d },' % (approxname,
+ # len(enumfields),))
+ comment = None
else:
- size_align = ' (size_t)-1, -1, -1, 0 /* %s */ },' % (
- reason_for_not_expanding,)
+ size = -1
+ align = -1
+ first_field_index = -1
+ comment = reason_for_not_expanding
self._lsts["struct_union"].append(
- ' { "%s", %d, %s,' % (tp.name, type_index, flags) + size_align)
+ StructUnionExpr(tp.name, type_index, flags, size, align, comment,
+ first_field_index, c_fields))
self._seen_struct_unions.add(tp)
def _add_missing_struct_unions(self):
@@ -770,15 +834,6 @@
(tp,))
self._struct_ctx(tp, None, approxname)
- def _fix_final_field_list(self, lst):
- count = 0
- for struct_fields in lst:
- pname = struct_fields.split('\n')[0]
- define_macro = '#define _cffi_FIELDS_FOR_%s %d' % (pname, count)
- result = define_macro + struct_fields[len(pname):]
- count += result.count('\n { "')
- yield result
-
def _generate_cpy_struct_collecttype(self, tp, name):
self._struct_collecttype(tp)
_generate_cpy_union_collecttype = _generate_cpy_struct_collecttype
diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
--- a/testing/cffi1/test_dlopen.py
+++ b/testing/cffi1/test_dlopen.py
@@ -68,3 +68,17 @@
_enums = (b'\x00\x00\x00\x00\x00\x00\x00\x15myenum_e\x00AA,BB,CC',),
)
"""
+
+def test_struct():
+ ffi = FFI()
+ ffi.cdef("struct foo_s { int a; signed char b[]; }; struct bar_s;")
+ target = udir.join('test_struct.py')
+ assert make_py_source(ffi, 'test_struct', str(target))
+ assert target.read() == r"""# auto-generated file
+import _cffi_backend
+
+ffi = _cffi_backend.FFI(b'test_struct',
+ _types = b'\x00\x00\x07\x01\x00\x00\x03\x01\x00\x00\x01\x07\x00\x00\x00\x09\x00\x00\x01\x09',
+ _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x10bar_s',),(b'\x00\x00\x00\x04\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x11a',b'\x00\x00\x02\x11b')),
+)
+"""
More information about the pypy-commit
mailing list