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

Reply via email to