Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit