Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1728:e5ba5bbdb223 Date: 2015-04-16 12:19 +0200 http://bitbucket.org/cffi/cffi/changeset/e5ba5bbdb223/
Log: More about constants diff --git a/new/cffi_opcode.py b/new/cffi_opcode.py --- a/new/cffi_opcode.py +++ b/new/cffi_opcode.py @@ -23,11 +23,13 @@ OP_FUNCTION_END = 15 OP_NOOP = 17 OP_BITFIELD = 19 -OP_INTEGER_CONST = 21 +OP_TYPENAME = 21 OP_CPYTHON_BLTN_V = 23 # varargs OP_CPYTHON_BLTN_N = 25 # noargs OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) -OP_TYPENAME = 29 +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 PRIM_VOID = 0 PRIM_BOOL = 1 diff --git a/new/ffi_obj.c b/new/ffi_obj.c --- a/new/ffi_obj.c +++ b/new/ffi_obj.c @@ -66,7 +66,6 @@ if (!ffi->ctx_is_static) { const void *mem[] = {ffi->info.ctx->types, ffi->info.ctx->globals, - ffi->info.ctx->constants, ffi->info.ctx->struct_unions, ffi->info.ctx->fields, ffi->info.ctx->enums, diff --git a/new/lib_obj.c b/new/lib_obj.c --- a/new/lib_obj.c +++ b/new/lib_obj.c @@ -111,9 +111,46 @@ x = lib_build_cpython_func(lib, g, s, METH_O); break; - case _CFFI_OP_NOOP: - /* this is used for global variables, of the exact type specified - here */ + case _CFFI_OP_CONSTANT_INT: + { + /* a constant integer whose value, in an "unsigned long long", + is obtained by calling the function at g->address */ + unsigned long long value; + int neg = ((int(*)(unsigned long long*))g->address)(&value); + if (!neg) { + if (value <= (unsigned long long)LONG_MAX) + x = PyInt_FromLong((long)value); + else + x = PyLong_FromUnsignedLongLong(value); + } + else { + if ((long long)value >= (long long)LONG_MIN) + x = PyInt_FromLong((long)value); + else + x = PyLong_FromLongLong((long long)value); + } + break; + } + + case _CFFI_OP_CONSTANT: + { + /* a constant which is not of integer type */ + char *data; + ct = realize_c_type(lib->l_ctx, lib->l_ctx->types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + + assert(ct->ct_size > 0); + data = alloca(ct->ct_size); + ((void(*)(char*))g->address)(data); + x = convert_to_object(data, ct); + Py_DECREF(ct); + break; + } + + case _CFFI_OP_GLOBAL_VAR: + /* global variable of the exact type specified here */ ct = realize_c_type(lib->l_ctx, lib->l_ctx->types, _CFFI_GETARG(g->type_op)); if (ct == NULL) diff --git a/new/manual.c b/new/manual.c --- a/new/manual.c +++ b/new/manual.c @@ -1,6 +1,10 @@ #include "_cffi_include.h" +#define AA (42) +#define BB (&bb) +static int bb = 16261; + int foo42(int a, int *b) { return a - *b; @@ -79,7 +83,21 @@ return _cffi_from_c_int(result, int); } +static int _cffi_const_AA(unsigned long long *output) +{ + *output = (unsigned long long)((AA) << 0); // integer + return (AA) <= 0; +} + +static void _cffi_const_BB(char *output) +{ + *(int **)output = BB; +} + static const struct _cffi_global_s _cffi_globals[] = { + { "AA", &_cffi_const_AA, _CFFI_OP(_CFFI_OP_CONSTANT_INT, 0) }, + { "BB", &_cffi_const_BB, _CFFI_OP(_CFFI_OP_CONSTANT, 2) }, + { "bb", &bb, _CFFI_OP(_CFFI_OP_VARIABLE, 2) }, { "foo42", &_cffi_f_foo42, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 0) }, { "foo64", &_cffi_f_foo64, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 4) }, }; @@ -92,7 +110,7 @@ NULL, NULL, NULL, - 2, /* num_globals */ + 5, /* num_globals */ 0, 0, 0, diff --git a/new/parse_c_type.h b/new/parse_c_type.h --- a/new/parse_c_type.h +++ b/new/parse_c_type.h @@ -17,11 +17,13 @@ #define _CFFI_OP_FUNCTION_END 15 #define _CFFI_OP_NOOP 17 #define _CFFI_OP_BITFIELD 19 -#define _CFFI_OP_INTEGER_CONST 21 +#define _CFFI_OP_TYPENAME 21 #define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs #define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs #define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) -#define _CFFI_OP_TYPENAME 29 +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 #define _CFFI_PRIM_VOID 0 #define _CFFI_PRIM_BOOL 1 @@ -64,12 +66,6 @@ _cffi_opcode_t type_op; }; -struct _cffi_constant_s { - const char *name; - unsigned long long value; - _cffi_opcode_t type_op; -}; - struct _cffi_struct_union_s { const char *name; size_t size; @@ -102,13 +98,11 @@ struct _cffi_type_context_s { _cffi_opcode_t *types; const struct _cffi_global_s *globals; - const struct _cffi_constant_s *constants; const struct _cffi_struct_union_s *struct_unions; const struct _cffi_field_s *fields; const struct _cffi_enum_s *enums; const struct _cffi_typename_s *typenames; int num_globals; - int num_constants; int num_struct_unions; int num_enums; int num_typenames; diff --git a/new/recompiler.py b/new/recompiler.py --- a/new/recompiler.py +++ b/new/recompiler.py @@ -133,14 +133,13 @@ prnt() # # XXX - nums['constant'] = 0 nums['struct_union'] = 0 nums['enum'] = 0 # # the declaration of '_cffi_type_context' prnt('static const struct _cffi_type_context_s _cffi_type_context = {') prnt(' _cffi_types,') - ALL_STEPS = ["global", "constant", "struct_union", "enum", "typename"] + ALL_STEPS = ["global", "struct_union", "enum", "typename"] for step_name in ALL_STEPS: if nums[step_name] > 0: prnt(' _cffi_%ss,' % step_name) @@ -354,10 +353,69 @@ else: meth_kind = 'V' # 'METH_VARARGS' self._lsts["global"].append( - ' { "%s", _cffi_f_%s, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d)},' + ' { "%s", _cffi_f_%s, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d) },' % (name, name, meth_kind, type_index)) # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + assert check_value is None # XXX + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' *o = (unsigned long long)((%s) << 0);' + ' /* check that we get an integer */' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + type_index = self._typesdict[tp] + type_op = '_CFFI_OP(_CFFI_OP_CONSTANT, %d)' % type_index + else: + type_op = '_CFFI_OP(_CFFI_OP_CONSTANT_INT, 0)' + self._lsts["global"].append( + ' { "%s", _cffi_const_%s, %s },' % (name, name, type_op)) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + self._lsts["global"].append( + ' { "%s", _cffi_const_%s, _CFFI_OP(_CFFI_OP_CONSTANT_INT, 0) },' % + (name, name)) + + # ---------- # global variables def _generate_cpy_variable_collecttype(self, tp, name): @@ -369,7 +427,7 @@ def _generate_cpy_variable_ctx(self, tp, name): type_index = self._typesdict[tp] self._lsts["global"].append( - ' { "%s", &%s, _CFFI_OP(_CFFI_OP_NOOP, %d)},' + ' { "%s", &%s, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, %d)},' % (name, name, type_index)) # ---------- @@ -395,6 +453,8 @@ def _emit_bytecode_PointerType(self, tp, index): self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + def _emit_bytecode_FunctionPtrType(self, tp, index): raw = tp.as_raw_function() self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) diff --git a/new/test_recompiler.py b/new/test_recompiler.py --- a/new/test_recompiler.py +++ b/new/test_recompiler.py @@ -99,12 +99,42 @@ py.test.raises(AttributeError, "del lib.c") py.test.raises(AttributeError, "del lib.foobarbaz") +def test_macro(): + ffi = FFI() + ffi.cdef("#define FOOBAR ...") + lib = verify(ffi, 'test_macro', "#define FOOBAR (-6912)") + assert lib.FOOBAR == -6912 + py.test.raises(AttributeError, "lib.FOOBAR = 2") + +def test_constant(): + ffi = FFI() + ffi.cdef("static const int FOOBAR;") + lib = verify(ffi, 'test_constant', "#define FOOBAR (-6912)") + assert lib.FOOBAR == -6912 + py.test.raises(AttributeError, "lib.FOOBAR = 2") + +def test_constant_nonint(): + ffi = FFI() + ffi.cdef("static const double FOOBAR;") + lib = verify(ffi, 'test_constant_nonint', "#define FOOBAR (-6912.5)") + assert lib.FOOBAR == -6912.5 + py.test.raises(AttributeError, "lib.FOOBAR = 2") + +def test_constant_ptr(): + ffi = FFI() + ffi.cdef("static double *const FOOBAR;") + lib = verify(ffi, 'test_constant_ptr', "#define FOOBAR NULL") + py.test.skip("XXX in-progress:") + assert lib.FOOBAR == ffi.NULL + assert ffi.typeof(lib.FOOBAR) == ffi.typeof("double *") + def test_dir(): ffi = FFI() - ffi.cdef("int ff(int); int aa;") + ffi.cdef("int ff(int); int aa; static const int my_constant;") lib = verify(ffi, 'test_dir', """ + #define my_constant (-45) int aa; int ff(int x) { return x+aa; } """) lib.aa = 5 - assert dir(lib) == ['aa', 'ff'] + assert dir(lib) == ['aa', 'ff', 'my_constant'] _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit