[pypy-commit] cffi cffi-1.0: Copy more code from vengine_cpy, and generate the remaining parts of the

arigo noreply at buildbot.pypy.org
Wed Apr 15 18:51:58 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1714:66428c0f8a54
Date: 2015-04-15 18:52 +0200
http://bitbucket.org/cffi/cffi/changeset/66428c0f8a54/

Log:	Copy more code from vengine_cpy, and generate the remaining parts of
	the example "manual.c"

diff --git a/new/cffi_opcode.py b/new/cffi_opcode.py
--- a/new/cffi_opcode.py
+++ b/new/cffi_opcode.py
@@ -3,8 +3,9 @@
     def __init__(self, op, arg):
         self.op = op
         self.arg = arg
-    def as_int(self):
-        return self.op | (self.arg << 8)
+    def as_c_expr(self):
+        classname = CLASS_NAME[self.op]
+        return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg)
     def __str__(self):
         classname = CLASS_NAME.get(self.op, self.op)
         return '(%s %d)' % (classname, self.arg)
diff --git a/new/recompiler.py b/new/recompiler.py
--- a/new/recompiler.py
+++ b/new/recompiler.py
@@ -5,8 +5,9 @@
 
 class Recompiler:
 
-    def __init__(self, ffi):
+    def __init__(self, ffi, module_name):
         self.ffi = ffi
+        self.module_name = module_name
 
     def collect_type_table(self):
         self._typesdict = {}
@@ -113,20 +114,272 @@
     def write_source_to_f(self, f, preamble):
         self._f = f
         prnt = self._prnt
-        # first copy some standard set of lines that are mostly '#define'
-        filename = os.path.join(os.path.dirname(__file__), '_cffi_include.h')
-        with open(filename, 'r') as g:
-            prnt(g.read())
+        #
+        # first the '#include'
+        prnt('#include "_cffi_include.h"')
+        #
+        # then paste the C source given by the user, verbatim.
         prnt('/************************************************************/')
         prnt()
-        # then paste the C source given by the user, verbatim.
         prnt(preamble)
         prnt()
-        #...
-        
+        prnt('/************************************************************/')
+        prnt()
+        #
+        # the declaration of '_cffi_types'
+        prnt('static void *_cffi_types[] = {')
+        for op in self.cffi_types:
+            prnt('  %s,' % (op.as_c_expr(),))
+        if not self.cffi_types:
+            prnt('  0')
+        prnt('};')
+        prnt()
+        #
+        # call generate_cpy_xxx_decl(), for every xxx found from
+        # ffi._parser._declarations.  This generates all the functions.
+        self._generate("decl")
+        #
+        # the declaration of '_cffi_globals'
+        self._lst = []
+        self._generate("global")
+        num_globals = len(self._lst)
+        if num_globals > 0:
+            self._lst.sort()  # sort by name, which is at the start of each line
+            prnt('static const struct _cffi_global_s _cffi_globals[] = {')
+            for line in self._lst:
+                prnt(line)
+            prnt('};')
+            prnt()
+        #
+        # XXX
+        num_constants = 0
+        num_structs_unions = 0
+        num_enums = 0
+        num_typenames = 0
+        #
+        # the declaration of '_cffi_type_context'
+        prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
+        prnt('  _cffi_types,')
+        if num_globals > 0:
+            prnt('  _cffi_globals,')
+        else:
+            prnt('  NULL,  /* no globals */')
+        if num_constants > 0:
+            prnt('  _cffi_constants,')
+        else:
+            prnt('  NULL,  /* no constants */')
+        if num_structs_unions > 0:
+            prnt('  _cffi_structs_unions,')
+            prnt('  _cffi_fields,')
+        else:
+            prnt('  NULL,  /* no structs */')
+            prnt('  NULL,  /* no fields */')
+        if num_enums > 0:
+            prnt('  _cffi_enums,')
+        else:
+            prnt('  NULL,  /* no enums */')
+        if num_typenames > 0:
+            prnt('  _cffi_typenames,')
+        else:
+            prnt('  NULL,  /* no typenames */')
+        prnt('  %d,  /* num_globals */' % num_globals)
+        prnt('  %d,  /* num_constants */' % num_constants)
+        prnt('  %d,  /* num_structs_unions */' % num_structs_unions)
+        prnt('  %d,  /* num_enums */' % num_enums)
+        prnt('  %d,  /* num_typenames */' % num_typenames)
+        prnt('};')
+        prnt()
+        #
+        # the init function, loading _cffi1_backend and calling a method there
+        prnt('PyMODINIT_FUNC')
+        prnt('init%s(void)' % (self.module_name,))
+        prnt('{')
+        prnt('  if (_cffi_init() < 0)')
+        prnt('    return;')
+        prnt('  _cffi_init_module("%s", &_cffi_type_context);' % (
+            self.module_name,))
+        prnt('}')
+
+    # ----------
+
+    def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
+        extraarg = ''
+        if isinstance(tp, model.PrimitiveType):
+            if tp.is_integer_type() and tp.name != '_Bool':
+                converter = '_cffi_to_c_int'
+                extraarg = ', %s' % tp.name
+            else:
+                converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
+                                                   tp.name.replace(' ', '_'))
+            errvalue = '-1'
+        #
+        elif isinstance(tp, model.PointerType):
+            self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
+                                                    tovar, errcode)
+            return
+        #
+        elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
+            # a struct (not a struct pointer) as a function argument
+            self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
+                      % (tovar, self._gettypenum(tp), fromvar))
+            self._prnt('    %s;' % errcode)
+            return
+        #
+        elif isinstance(tp, model.FunctionPtrType):
+            converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
+            extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
+            errvalue = 'NULL'
+        #
+        else:
+            raise NotImplementedError(tp)
+        #
+        self._prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
+        self._prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
+            tovar, tp.get_c_name(''), errvalue))
+        self._prnt('    %s;' % errcode)
+
+    def _extra_local_variables(self, tp, localvars):
+        if isinstance(tp, model.PointerType):
+            localvars.add('Py_ssize_t datasize')
+
+    def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
+        self._prnt('  datasize = _cffi_prepare_pointer_call_argument(')
+        self._prnt('      _cffi_type(%d), %s, (char **)&%s);' % (
+            self._gettypenum(tp), fromvar, tovar))
+        self._prnt('  if (datasize != 0) {')
+        self._prnt('    if (datasize < 0)')
+        self._prnt('      %s;' % errcode)
+        self._prnt('    %s = alloca((size_t)datasize);' % (tovar,))
+        self._prnt('    memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
+        self._prnt('    if (_cffi_convert_array_from_object('
+                   '(char *)%s, _cffi_type(%d), %s) < 0)' % (
+            tovar, self._gettypenum(tp), fromvar))
+        self._prnt('      %s;' % errcode)
+        self._prnt('  }')
+
+    def _convert_expr_from_c(self, tp, var, context):
+        if isinstance(tp, model.PrimitiveType):
+            if tp.is_integer_type():
+                return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
+            elif tp.name != 'long double':
+                return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
+            else:
+                return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
+                    var, self._gettypenum(tp))
+        elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
+            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
+                var, self._gettypenum(tp))
+        elif isinstance(tp, model.ArrayType):
+            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
+                var, self._gettypenum(model.PointerType(tp.item)))
+        elif isinstance(tp, model.StructType):
+            if tp.fldnames is None:
+                raise TypeError("'%s' is used as %s, but is opaque" % (
+                    tp._get_c_name(), context))
+            return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
+                var, self._gettypenum(tp))
+        elif isinstance(tp, model.EnumType):
+            return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
+                var, self._gettypenum(tp))
+        else:
+            raise NotImplementedError(tp)
+
+    # ----------
+    # function declarations
+
+    def _generate_cpy_function_decl(self, tp, name):
+        assert isinstance(tp, model.FunctionPtrType)
+        if tp.ellipsis:
+            # cannot support vararg functions better than this: check for its
+            # exact type (including the fixed arguments), and build it as a
+            # constant function pointer (no CPython wrapper)
+            self._generate_cpy_const(False, name, tp)
+            return
+        prnt = self._prnt
+        numargs = len(tp.args)
+        if numargs == 0:
+            argname = 'noarg'
+        elif numargs == 1:
+            argname = 'arg0'
+        else:
+            argname = 'args'
+        prnt('static PyObject *')
+        prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
+        prnt('{')
+        #
+        context = 'argument of %s' % name
+        for i, type in enumerate(tp.args):
+            prnt('  %s;' % type.get_c_name(' x%d' % i, context))
+        #
+        localvars = set()
+        for type in tp.args:
+            self._extra_local_variables(type, localvars)
+        for decl in localvars:
+            prnt('  %s;' % (decl,))
+        #
+        if not isinstance(tp.result, model.VoidType):
+            result_code = 'result = '
+            context = 'result of %s' % name
+            prnt('  %s;' % tp.result.get_c_name(' result', context))
+        else:
+            result_code = ''
+        #
+        if len(tp.args) > 1:
+            rng = range(len(tp.args))
+            for i in rng:
+                prnt('  PyObject *arg%d;' % i)
+            prnt()
+            prnt('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
+                'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
+            prnt('    return NULL;')
+        prnt()
+        #
+        for i, type in enumerate(tp.args):
+            self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
+                                       'return NULL')
+            prnt()
+        #
+        prnt('  Py_BEGIN_ALLOW_THREADS')
+        prnt('  _cffi_restore_errno();')
+        prnt('  { %s%s(%s); }' % (
+            result_code, name,
+            ', '.join(['x%d' % i for i in range(len(tp.args))])))
+        prnt('  _cffi_save_errno();')
+        prnt('  Py_END_ALLOW_THREADS')
+        prnt()
+        #
+        prnt('  (void)self; /* unused */')
+        if numargs == 0:
+            prnt('  (void)noarg; /* unused */')
+        if result_code:
+            prnt('  return %s;' %
+                 self._convert_expr_from_c(tp.result, 'result', 'result type'))
+        else:
+            prnt('  Py_INCREF(Py_None);')
+            prnt('  return Py_None;')
+        prnt('}')
+        prnt()
+
+    def _generate_cpy_function_global(self, tp, name):
+        if tp.ellipsis:
+            XXX
+        type_index = self._typesdict[tp.as_raw_function()]
+        numargs = len(tp.args)
+        if numargs == 0:
+            meth_kind = 'N'   # 'METH_NOARGS'
+        elif numargs == 1:
+            meth_kind = 'O'   # 'METH_O'
+        else:
+            meth_kind = 'V'   # 'METH_VARARGS'
+        self._lst.append(
+            '  { "%s", _cffi_f_%s, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d)},'
+            % (name, name, meth_kind, type_index))
+
 
 def make_c_source(ffi, target_c_file, preamble):
-    recompiler = Recompiler(ffi)
+    module_name, ext = os.path.splitext(os.path.basename(target_c_file))
+    assert ext, "no extension!"
+    recompiler = Recompiler(ffi, module_name)
     recompiler.collect_type_table()
     with open(target_c_file, 'w') as f:
         recompiler.write_source_to_f(f, preamble)
diff --git a/new/test_recompiler.py b/new/test_recompiler.py
--- a/new/test_recompiler.py
+++ b/new/test_recompiler.py
@@ -6,7 +6,7 @@
 def check_type_table(input, expected_output):
     ffi = FFI()
     ffi.cdef(input)
-    recompiler = Recompiler(ffi)
+    recompiler = Recompiler(ffi, 'testmod')
     recompiler.collect_type_table()
     assert ''.join(map(str, recompiler.cffi_types)) == expected_output
 
@@ -38,5 +38,5 @@
 
 def test_math_sin():
     ffi = FFI()
-    ffi.cdef("double sin(double);")
+    ffi.cdef("float sin(double); double cos(double);")
     make_c_source(ffi, str(udir.join('math_sin.c')), '#include <math.h>')


More information about the pypy-commit mailing list