[pypy-commit] cffi default: add support for long/long long C integer constant suffixes, and support

guil...@Guillaumes-MacBook-Pro.local pypy.commits at gmail.com
Wed Mar 27 06:45:20 EDT 2019


Author: guillaumesottas at Guillaumes-MacBook-Pro.local
Branch: 
Changeset: r3249:d1bf39c55881
Date: 2019-03-26 13:09 -0600
http://bitbucket.org/cffi/cffi/changeset/d1bf39c55881/

Log:	add support for long/long long C integer constant suffixes, and
	support for base 2 integer constant as well.

diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -817,12 +817,22 @@
         # or positive/negative number
         if isinstance(exprnode, pycparser.c_ast.Constant):
             s = exprnode.value
-            if s.startswith('0'):
-                if s.startswith('0x') or s.startswith('0X'):
-                    if s.endswith('u') or s.endswith('U'):
-                        s = s[:-1]
-                    return int(s, 16)
-                return int(s, 8)
+            if '0' <= s[0] <= '9':
+                s = s.rstrip('uUlL')  # remove integer constant suffix if any. this will remove pattern such as lL, but
+                # it is the responsibility of the C parser to perform this check.
+                try:  # first we try to convert to base 8/10, as it will fail if the string contains base 2/16 C prefix.
+                    if s.startswith('0'):
+                        return int(s, 8)
+                    else:
+                        return int(s, 10)
+                except ValueError:  # then it should be a base 2 or a base 16. it is necessary to explicitly check the
+                    # prefix, as python's int() function will be able to convert both (0b01 and 0x0b01) into base 16.
+                    if len(s) > 1:
+                        if s.lower()[0:2] == '0x':
+                            return int(s, 16)
+                        elif s.lower()[0:2] == '0b':
+                            return int(s, 2)
+                raise CDefError("invalid constant %r" % (s,))
             elif '1' <= s[0] <= '9':
                 return int(s, 10)
             elif s[0] == "'" and s[-1] == "'" and (
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -470,6 +470,39 @@
 def test_unsigned_int_suffix_for_constant():
     ffi = FFI()
     ffi.cdef("""enum e {
-                    enumerator_0=0x00,
-                    enumerator_1=0x01u,
-                    enumerator_1=0x01U};""")
+                    bin_0=0b10,
+                    bin_1=0b10u,
+                    bin_2=0b10U,
+                    bin_3=0b10l,
+                    bin_4=0b10L,
+                    bin_5=0b10ll,
+                    bin_6=0b10LL,
+                    oct_0=010,
+                    oct_1=010u,
+                    oct_2=010U,
+                    oct_3=010l,
+                    oct_4=010L,
+                    oct_5=010ll,
+                    oct_6=010LL,
+                    dec_0=10,
+                    dec_1=10u,
+                    dec_2=10U,
+                    dec_3=10l,
+                    dec_4=10L,
+                    dec_5=10ll,
+                    dec_6=10LL,
+                    hex_0=0x10,
+                    hex_1=0x10u,
+                    hex_2=0x10U,
+                    hex_3=0x10l,
+                    hex_4=0x10L,
+                    hex_5=0x10ll,
+                    hex_6=0x10LL,};""")
+    needs_dlopen_none()
+    C = ffi.dlopen(None)
+    for base, expected_result in (('bin', 2), ('oct', 8), ('dec', 10), ('hex', 16)):
+        for index in range(7):
+            try:
+                assert getattr(C, '{base}_{index}'.format(base=base, index=index)) == expected_result
+            except AssertionError as e:
+                raise e


More information about the pypy-commit mailing list