[pypy-commit] creflect default: Functions!
arigo
noreply at buildbot.pypy.org
Tue Nov 18 00:03:58 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r60:a5c04855d4c6
Date: 2014-11-18 00:04 +0100
http://bitbucket.org/cffi/creflect/changeset/a5c04855d4c6/
Log: Functions!
diff --git a/creflect/codegen.py b/creflect/codegen.py
--- a/creflect/codegen.py
+++ b/creflect/codegen.py
@@ -4,7 +4,14 @@
def __init__(self, parent):
self.decllines = []
self.codelines = []
- self.crx_type_vars = [] if parent is None else parent.crx_type_vars
+ if parent is None:
+ self.crx_type_vars = []
+ self.crx_type_cache = {}
+ self.crx_top_level = self
+ else:
+ self.crx_type_vars = parent.crx_type_vars
+ self.crx_type_cache = parent.crx_type_cache
+ self.crx_top_level = parent.crx_top_level
def writedecl(self, line):
self.decllines.append(line)
@@ -18,15 +25,31 @@
self.writeline(" " + line)
self.writeline("}")
- def add_crx_type_var(self):
- name = 't%d' % (len(self.crx_type_vars) + 1)
- self.crx_type_vars.append('*%s' % name)
- return name
+ def _get_next_name(self, prefix):
+ return '%s%d' % (prefix, len(self.crx_type_vars) + 1)
+ def write_crx_type_var(self, expr):
+ if expr in self.crx_type_cache:
+ return self.crx_type_cache[expr]
+ #
+ t1 = self._get_next_name('t')
+ self.crx_type_vars.append('*%s' % t1)
+ self.crx_type_cache[expr] = t1
+ self.writeline('%s = %s;' % (t1, expr))
+ return t1
-def transform_cdef(csource, creflect_func_name):
+ def add_array_crx_types(self, array_size):
+ if array_size > 0:
+ a1 = self._get_next_name('a')
+ self.crx_type_vars.append('*%s[%d]' % (a1, array_size))
+ return a1
+ else:
+ return '0'
+
+
+def transform_cdef(csource, crx_func_name):
outerblock = CodeBlock(parent=None)
- outerblock.writeline('void %s(crx_builder_t *cb)' % (creflect_func_name,))
+ outerblock.crx_func_name = crx_func_name
funcblock = CodeBlock(outerblock)
@@ -37,6 +60,7 @@
funcblock.writedecl("crx_type_t %s;" % (
', '.join(funcblock.crx_type_vars),))
+ outerblock.writeline('void %s(crx_builder_t *cb)' % (crx_func_name,))
outerblock.write_subblock(funcblock)
outerblock.writeline('') # for the final \n below
return '\n'.join(outerblock.codelines)
diff --git a/creflect/cparser.py b/creflect/cparser.py
--- a/creflect/cparser.py
+++ b/creflect/cparser.py
@@ -94,8 +94,8 @@
node = decl.type
if isinstance(node, pycparser.c_ast.FuncDecl):
tp = self._get_type(node)
- assert isinstance(tp, model.RawFunctionType)
- tp = self._get_type_pointer(tp)
+ assert isinstance(tp, model.FunctionType)
+ tp = model.PointerType(tp)
self._declare('function ' + decl.name, tp)
else:
const = 'const' in decl.quals
@@ -135,11 +135,6 @@
realtype = self._get_type(decl.type, approx_name = '$' + decl.name)
self.declarations.append(model.TypeDefDecl(decl.name, realtype))
- def _get_type_pointer(self, type, const):
- if isinstance(type, model.RawFunctionType):
- return type.as_function_pointer()
- return model.PointerType(type, const)
-
def _get_type(self, typenode, approx_name=None, partial_length_ok=False):
# first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
@@ -165,7 +160,7 @@
if approx_name:
approx_name = '$' + approx_name
realtype = self._get_type(typenode.type, approx_name)
- return self._get_type_pointer(realtype, const)
+ return model.PointerType(realtype, const)
#
if isinstance(typenode, pycparser.c_ast.TypeDecl):
const = 'const' in typenode.quals
@@ -191,7 +186,7 @@
#
if isinstance(typenode, pycparser.c_ast.FuncDecl):
# a function type
- return self._parse_function_type(typenode, name)
+ return self._parse_function_type(typenode, approx_name)
#
# nested anonymous structs or unions end up here
if isinstance(typenode, pycparser.c_ast.Struct):
@@ -204,6 +199,36 @@
raise api.FFIError(":%d: bad or unsupported type declaration" %
typenode.coord.line)
+ def _parse_function_type(self, typenode, funcname=None):
+ params = list(getattr(typenode.args, 'params', []))
+ ellipsis = (
+ len(params) > 0 and
+ isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and
+ isinstance(params[-1].type.type,
+ pycparser.c_ast.IdentifierType) and
+ params[-1].type.type.names == ['__dotdotdot__'])
+ if ellipsis:
+ params.pop()
+ if not params:
+ raise api.CDefError(
+ "%s: a function with only '(...)' as argument"
+ " is not correct C" % (funcname or 'in expression'))
+ elif (len(params) == 1 and
+ isinstance(params[0].type, pycparser.c_ast.TypeDecl) and
+ isinstance(params[0].type.type, pycparser.c_ast.IdentifierType)
+ and list(params[0].type.type.names) == ['void']):
+ del params[0]
+ args = [self._as_func_arg(self._get_type(argdeclnode.type))
+ for argdeclnode in params]
+ result = self._get_type(typenode.type)
+ return model.FunctionType(tuple(args), result, ellipsis)
+
+ def _as_func_arg(self, type):
+ if isinstance(type, (model.ArrayType, model.FunctionType)):
+ return model.PointerType(type.item)
+ else:
+ return type
+
def _get_struct_union_enum_type(self, kind, type, const, approx_name=None):
name = type.name or approx_name
if not name or name.startswith('$$$'):
diff --git a/creflect/creflect.h b/creflect/creflect.h
--- a/creflect/creflect.h
+++ b/creflect/creflect.h
@@ -10,7 +10,7 @@
} crx_field_t;
typedef struct crx_type_s crx_type_t; /* opaque */
-typedef void (*crx_trampoline_t)(void *fn, void *args[], void *res);
+typedef void (*crx_trampoline_fn)(void *fn, void *args[], void *res);
#define CRX_SELF struct _crx_builder_s *
typedef struct _crx_builder_s {
@@ -24,7 +24,7 @@
crx_type_t *(*get_float_type)(CRX_SELF, size_t,
const char *);
crx_type_t *(*get_function_type)(CRX_SELF, crx_type_t *,
- crx_type_t *[], int, crx_trampoline_t *);
+ crx_type_t *[], int, crx_trampoline_fn);
crx_type_t *(*get_ellipsis_function_type)(CRX_SELF, crx_type_t *,
crx_type_t *[], int);
crx_type_t *(*get_pointer_type)(CRX_SELF, crx_type_t *);
diff --git a/creflect/model.py b/creflect/model.py
--- a/creflect/model.py
+++ b/creflect/model.py
@@ -2,13 +2,12 @@
class BaseType(object):
- is_array_type = False
- def _get_c_name(self):
- return self.c_name_with_marker.replace('&', '')
+ def get_c_name(self, replace_with=''):
+ return self.c_name_with_marker.replace('&', replace_with).rstrip()
def __repr__(self):
- return '<%s>' % (self._get_c_name(),)
+ return '<%s>' % (self.get_c_name(),)
def _get_items(self):
return [(name, getattr(self, name))
@@ -17,15 +16,17 @@
def inspect_type(self, block, inspect):
t1 = self.inspect_nonconst_type(block, inspect)
if self.const:
- t2 = block.add_crx_type_var()
- block.writeline('%s = cb->get_const_type(cb, %s);' % (t2, t1))
- return t2
+ return block.write_crx_type_var('cb->get_const_type(cb, %s)' % t1)
else:
return t1
def inspect_nonconst_type(self, block, inspect):
raise NotImplementedError
+ def _flush_inspect(self, inspect):
+ if inspect is not None and inspect.started:
+ inspect.assign_to_p1('0')
+
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self._get_items() == other._get_items())
@@ -43,13 +44,12 @@
def __init__(self, const):
self.const = const
self.c_name_with_marker = 'void &'
+ if const:
+ self.c_name_with_marker = 'const ' + self.c_name_with_marker
def inspect_nonconst_type(self, block, inspect):
- if inspect.started:
- inspect.assign_to_p1('0')
- t1 = block.add_crx_type_var()
- block.writeline('%s = cb->get_void_type(cb);' % (t1,))
- return t1
+ self._flush_inspect(inspect)
+ return block.write_crx_type_var('cb->get_void_type(cb)')
void_type = VoidType(const=False)
const_void_type = VoidType(const=True)
@@ -65,15 +65,15 @@
'long': 'i',
'long long': 'i',
'signed char': 'i',
- 'unsigned char': 'i',
- 'unsigned short': 'i',
- 'unsigned int': 'i',
- 'unsigned long': 'i',
- 'unsigned long long': 'i',
+ 'unsigned char': 'u',
+ 'unsigned short': 'u',
+ 'unsigned int': 'u',
+ 'unsigned long': 'u',
+ 'unsigned long long': 'u',
'float': 'f',
'double': 'f',
'long double': 'f',
- '_Bool': 'i',
+ '_Bool': 'u',
}
def __init__(self, name, const):
@@ -87,80 +87,147 @@
def is_char_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
def is_integer_type(self):
+ return self.ALL_PRIMITIVE_TYPES[self.name] in 'iu'
+ def is_signed_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
+ def is_unsigned_type(self):
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'u'
def is_float_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
def inspect_nonconst_type(self, block, inspect):
- star_p1 = inspect.fetch_star_p1()
- comment1 = inspect.get_comment(0, False, "a valid type", minlevel=1)
- comment2 = inspect.get_comment(0, False, "an integer type")
- comment3 = inspect.get_comment(0, False, "not declared 'const'")
- block.writedecl("char b[sizeof(%s)];%s" % (star_p1, comment1))
- if self.const:
- block.writeline("memset(b, -1, sizeof(b));")
- inspect.assign_to_p1("b")
- block.writeline("(void)(%s << 1);%s" % (star_p1, comment2))
- if not self.const:
- block.writeline("%s = -1;%s" % (star_p1, comment3))
- t1 = block.add_crx_type_var()
- if self.is_integer_type():
- block.writeline('%s = CRX_INT_TYPE(cb, %s, "%s");' % (
- t1, star_p1, self.name))
- elif self.is_char_type():
- block.writeline('%s = cb->get_char_type(cb);' % (t1,))
- elif self.is_float_type():
- xxx
+ if inspect is None:
+ if self.is_signed_type():
+ expr = 'cb->get_signed_type(cb, sizeof(%s), "%s")' % (
+ self.name, self.name)
+ elif self.is_unsigned_type():
+ expr = 'cb->get_unsigned_type(cb, sizeof(%s), "%s")' % (
+ self.name, self.name)
+ elif self.is_char_type():
+ expr = 'cb->get_char_type(cb)'
+ elif self.is_float_type():
+ xxx
+ else:
+ raise AssertionError
else:
- raise AssertionError
- return t1
+ star_p1 = inspect.fetch_star_p1()
+ comment1 = inspect.get_comment(0, False, "a valid type", minlevel=1)
+ comment2 = inspect.get_comment(0, False, "an integer type")
+ comment3 = inspect.get_comment(0, False, "not declared 'const'")
+ block.writedecl("char b[sizeof(%s)];%s" % (star_p1, comment1))
+ if self.const:
+ block.writeline("memset(b, -1, sizeof(b));")
+ inspect.assign_to_p1("b")
+ block.writeline("(void)(%s << 1);%s" % (star_p1, comment2))
+ if not self.const:
+ block.writeline("%s = -1;%s" % (star_p1, comment3))
+ if self.is_integer_type():
+ expr = 'CRX_INT_TYPE(cb, %s, "%s")' % (star_p1, self.name)
+ elif self.is_char_type():
+ expr = 'cb->get_char_type(cb)'
+ elif self.is_float_type():
+ xxx
+ else:
+ raise AssertionError
+ return block.write_crx_type_var(expr)
-class BaseFunctionType(BaseType):
- pass
+class FunctionType(BaseType):
+ _attrs_ = ('args', 'result', 'ellipsis')
+ const = True
-class RawFunctionType(BaseFunctionType):
- pass
+ def __init__(self, args, result, ellipsis):
+ self.args = args
+ self.result = result
+ self.ellipsis = ellipsis
+ #
+ reprargs = [arg.get_c_name() for arg in self.args]
+ if self.ellipsis:
+ reprargs.append('...')
+ reprargs = reprargs or ['void']
+ replace_with = '&(%s)' % (', '.join(reprargs),)
+ self.c_name_with_marker = (
+ self.result.c_name_with_marker.replace('&', replace_with))
+
+ def inspect_type(self, block, inspect):
+ # this class overrides inspect_type() instead of
+ # inspect_nonconst_type(), to avoid the extra call to get_const_type()
+ self._flush_inspect(inspect)
+ assert not self.ellipsis, "XXX"
+ t1 = self.result.inspect_type(block, None)
+ call = [' ']
+ if not isinstance(self.result, VoidType):
+ call.append('*(%s)result = ' % (self.result.get_c_name('*'),))
+ call.append('f(')
+ t_args = [arg.inspect_type(block, None) for arg in self.args]
+ a2 = block.add_array_crx_types(len(t_args))
+ for i, t in enumerate(t_args):
+ block.writeline('%s[%d] = %s;' % (a2, i, t))
+ if i > 0:
+ call.append(', ')
+ call.append('*(%s)args[%d]' % (self.args[i].get_c_name('*'), i))
+ call.append(');')
+ #
+ toplevel = block.crx_top_level
+ crx_func_name = '%s__%s' % (toplevel.crx_func_name,
+ block._get_next_name('f'))
+ wrline = toplevel.writeline
+ wrline('static void %s(void *func, void *args[], void *result) {' % (
+ crx_func_name,))
+ wrline(' func_t f = func;') # XXX!
+ wrline(''.join(call))
+ wrline('}')
+ wrline('')
+ expr = 'cb->get_function_type(cb, %s, %s, %d, &%s)' % (
+ t1, a2, len(t_args), crx_func_name)
+ return block.write_crx_type_var(expr)
+
class PointerType(BaseType):
_attrs_ = ('totype',)
+ _base_pattern = {
+ (False, False): "*&",
+ (True, False): "(*&)",
+ (False, True): "*const &",
+ (True, True): "(*const &)",
+ }
def __init__(self, totype, const):
self.totype = totype
self.const = const
base = self.totype.c_name_with_marker
- self.c_name_with_marker = base.replace('&', '(*&)')
+ parens = isinstance(self.totype, (ArrayType, FunctionType))
+ extra = self._base_pattern[parens, self.const]
+ self.c_name_with_marker = base.replace('&', extra)
def inspect_nonconst_type(self, block, inspect):
- star_p1 = inspect.fetch_star_p1()
- new_var = 'p%d' % (len(inspect.levels) + 2,)
- block.writedecl("char *%s;" % (new_var,))
- inspect.assign_to_p1("&%s" % (new_var,))
- #
- if self.const:
- errmsg = "type '%s' is not a pointer, but an array type" % (
- inspect.get_comment_type(0, False),)
- inspect.assign_target = new_var
- def after():
- ampersand_star_p1 = '&' + star_p1
- if ampersand_star_p1.startswith('&*'):
- ampersand_star_p1 = ampersand_star_p1[2:]
- block.writeline("if ((void *)%s == (void *)%s) {" % (
- ampersand_star_p1, star_p1))
- block.writeline(' cb->error(cb, "%s");' % (errmsg,))
- block.writeline(" return;")
- block.writeline("}")
- inspect.after_star_p1_assignment.append(after)
- inspect.levels.append('*')
+ if inspect is not None:
+ star_p1 = inspect.fetch_star_p1()
+ new_var = 'p%d' % (len(inspect.levels) + 2,)
+ block.writedecl("char *%s;" % (new_var,))
+ inspect.assign_to_p1("&%s" % (new_var,))
+ #
+ if self.const:
+ errmsg = "type '%s' is not a pointer, but an array type" % (
+ inspect.get_comment_type(0, False),)
+ inspect.assign_target = new_var
+ def after():
+ ampersand_star_p1 = '&' + star_p1
+ if ampersand_star_p1.startswith('&*'):
+ ampersand_star_p1 = ampersand_star_p1[2:]
+ block.writeline("if ((void *)%s == (void *)%s) {" % (
+ ampersand_star_p1, star_p1))
+ block.writeline(' cb->error(cb, "%s");' % (errmsg,))
+ block.writeline(" return;")
+ block.writeline("}")
+ inspect.after_star_p1_assignment.append(after)
+ inspect.levels.append('*')
t1 = self.totype.inspect_type(block, inspect)
- t2 = block.add_crx_type_var()
- block.writeline('%s = cb->get_pointer_type(cb, %s);' % (t2, t1))
- return t2
+ return block.write_crx_type_var('cb->get_pointer_type(cb, %s)' % t1)
class ArrayType(BaseType):
_attrs_ = ('item', 'length')
- is_array_type = True
const = True # not really applicable, but must have one
def __init__(self, item, length):
@@ -179,26 +246,25 @@
def inspect_type(self, block, inspect):
# this class overrides inspect_type() instead of
# inspect_nonconst_type(), to avoid the extra call to get_const_type()
- star_p1 = inspect.fetch_star_p1()
- errmsg = "type '%s' is not an array, but a pointer type" % (
- inspect.get_comment_type(0, False),)
- def after():
- ampersand_star_p1 = '&' + star_p1
- if ampersand_star_p1.startswith('&*'):
- ampersand_star_p1 = ampersand_star_p1[2:]
- block.writeline("if ((void *)%s != (void *)%s) {" % (
- ampersand_star_p1, star_p1))
- block.writeline(' cb->error(cb, "%s");' % (errmsg,))
- block.writeline(" return;")
- block.writeline("}")
- inspect.levels.append('[]')
- inspect.after_star_p1_assignment.append(after)
+ if inspect is not None:
+ star_p1 = inspect.fetch_star_p1()
+ errmsg = "type '%s' is not an array, but a pointer type" % (
+ inspect.get_comment_type(0, False),)
+ def after():
+ ampersand_star_p1 = '&' + star_p1
+ if ampersand_star_p1.startswith('&*'):
+ ampersand_star_p1 = ampersand_star_p1[2:]
+ block.writeline("if ((void *)%s != (void *)%s) {" % (
+ ampersand_star_p1, star_p1))
+ block.writeline(' cb->error(cb, "%s");' % (errmsg,))
+ block.writeline(" return;")
+ block.writeline("}")
+ inspect.levels.append('[]')
+ inspect.after_star_p1_assignment.append(after)
t1 = self.item.inspect_type(block, inspect)
- t2 = block.add_crx_type_var()
- block.writeline('%s = cb->get_array_type(cb, %s, '
- 'sizeof(%s) / sizeof(*%s));' % (
- t2, t1, star_p1, star_p1))
- return t2
+ expr = 'cb->get_array_type(cb, %s, sizeof(%s) / sizeof(*%s));' % (
+ t1, star_p1, star_p1)
+ return block.write_crx_type_var(expr)
class StructOrUnionOrEnum(BaseType):
diff --git a/test/cgcompile.c b/test/cgcompile.c
--- a/test/cgcompile.c
+++ b/test/cgcompile.c
@@ -80,9 +80,16 @@
static crx_type_t *tst_get_function_type(crx_builder_t *cb, crx_type_t *ret,
crx_type_t *args[], int nargs,
- crx_trampoline_t *trampl)
+ crx_trampoline_fn trampl)
{
- abort();
+ int i;
+ const char *prev = "FUNC( ";
+ for (i = 0; i < nargs; i++) {
+ prev = newtype2(prev, args[i]->text)->text;
+ prev = newtype2(prev, " -> ")->text;
+ }
+ prev = newtype2(prev, ret->text)->text;
+ return newtype2(prev, " )");
}
static crx_type_t *tst_get_ellipsis_function_type(crx_builder_t *cb,
diff --git a/test/codegen/func-003.c b/test/codegen/func-003.c
--- a/test/codegen/func-003.c
+++ b/test/codegen/func-003.c
@@ -1,15 +1,15 @@
-typedef int(*func_t)(long, long);
+typedef int(*func_t)(long, long, int);
# ____________________________________________________________
-static void __creflect_t3(void *func, void *args[], void *result) {
+static void testfunc_003__f4(void *func, void *args[], void *result) {
func_t f = func;
- *(int *)result = f(*(long *)args[0], *(long *)args[1]);
+ *(int *)result = f(*(long *)args[0], *(long *)args[1], *(int *)args[2]);
}
void testfunc_003(crx_builder_t *cb)
{
- crx_type *t1, *t2, *a3[2], *t3;
+ crx_type_t *t1, *t2, *a3[3], *t4, *t5;
{
func_t *p1;
char *p2;
@@ -19,7 +19,10 @@
t2 = cb->get_signed_type(cb, sizeof(long), "long");
a3[0] = t2;
a3[1] = t2;
- t3 = cb->get_function_type(cb, t1, a3, 2, &__creflect_t3);
- cb->define_type(cb, "func_t", t3);
+ a3[2] = t1;
+ t4 = cb->get_function_type(cb, t1, a3, 3, &testfunc_003__f4);
+ t5 = cb->get_pointer_type(cb, t4);
+ cb->define_type(cb, "func_t", t5);
+#expect TYPEDEF func_t = PTR FUNC( long -> long -> int -> int )
}
}
More information about the pypy-commit
mailing list