[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