[pypy-commit] cffi auto-types: Implementation
arigo
noreply at buildbot.pypy.org
Sun Feb 10 19:09:51 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch: auto-types
Changeset: r1142:ee2c2a732000
Date: 2013-02-10 18:52 +0100
http://bitbucket.org/cffi/cffi/changeset/ee2c2a732000/
Log: Implementation
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3214,7 +3214,7 @@
return NULL;
flag = CT_STRUCT;
- if (strcmp(name, "_IO_FILE") == 0)
+ if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
flag |= CT_IS_FILE;
return _b_struct_or_union_type("struct", name, flag);
}
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2505,7 +2505,7 @@
if sys.platform == "win32":
py.test.skip("testing FILE not implemented")
#
- BFILE = new_struct_type("_IO_FILE")
+ BFILE = new_struct_type("$FILE")
BFILEP = new_pointer_type(BFILE)
BChar = new_primitive_type("char")
BCharP = new_pointer_type(BChar)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -71,7 +71,6 @@
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
- self._parser._declarations['typedef FILE'] = model.file_type
BVoidP = self._get_cached_btype(model.voidp_type)
if isinstance(backend, types.ModuleType):
# _cffi_backend: attach these constants to the class
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -1,5 +1,6 @@
from . import api, model
+from .commontypes import COMMON_TYPES
import pycparser.c_parser, weakref, re, sys
try:
@@ -17,6 +18,7 @@
_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
+_r_words = re.compile(r"\w+|\S")
_parser_cache = None
def _get_parser():
@@ -58,10 +60,34 @@
# which is declared with a typedef for the purpose of C parsing.
return csource.replace('...', ' __dotdotdot__ '), macros
+def _common_type_names(csource):
+ # Look in the source for what looks like usages of types from the
+ # list of common types. A "usage" is approximated here as the
+ # appearance of the word, minus a "definition" of the type, which
+ # is the last word in a "typedef" statement. Approximative only
+ # but should be fine for all the common types.
+ look_for_words = set(COMMON_TYPES)
+ look_for_words.add(';')
+ look_for_words.add('typedef')
+ words_used = set()
+ is_typedef = False
+ previous_word = ''
+ for word in _r_words.findall(csource):
+ if word in look_for_words:
+ if word == ';':
+ if is_typedef:
+ words_used.discard(previous_word)
+ look_for_words.discard(previous_word)
+ is_typedef = False
+ elif word == 'typedef':
+ is_typedef = True
+ else: # word in COMMON_TYPES
+ words_used.add(word)
+ previous_word = word
+ return words_used
+
+
class Parser(object):
- TYPEDEFS = sorted(
- [_name for _name in model.PrimitiveType.ALL_PRIMITIVE_TYPES
- if _name.endswith('_t')])
def __init__(self):
self._declarations = {}
@@ -70,17 +96,23 @@
self._override = False
def _parse(self, csource):
+ csource, macros = _preprocess(csource)
# XXX: for more efficiency we would need to poke into the
# internals of CParser... the following registers the
# typedefs, because their presence or absence influences the
# parsing itself (but what they are typedef'ed to plays no role)
- typenames = self.TYPEDEFS[:]
+ ctn = _common_type_names(csource)
+ print `csource`, ctn
+ typenames = []
for name in sorted(self._declarations):
if name.startswith('typedef '):
- typenames.append(name[8:])
+ name = name[8:]
+ typenames.append(name)
+ ctn.discard(name)
+ typenames += sorted(ctn)
+ #
csourcelines = ['typedef int %s;' % typename for typename in typenames]
csourcelines.append('typedef int __dotdotdot__;')
- csource, macros = _preprocess(csource)
csourcelines.append(csource)
csource = '\n'.join(csourcelines)
if lock is not None:
@@ -267,6 +299,8 @@
return model.void_type
if ident == '__dotdotdot__':
raise api.FFIError('bad usage of "..."')
+ if ident in COMMON_TYPES:
+ return COMMON_TYPES[ident]
return model.PrimitiveType(ident)
#
if isinstance(type, pycparser.c_ast.Struct):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -73,9 +73,9 @@
'float': 'f',
'double': 'f',
'long double': 'f',
- 'wchar_t': 'c',
'_Bool': 'u',
# the following types are not primitive in the C sense
+ 'wchar_t': 'c',
'int8_t': 'i',
'uint8_t': 'u',
'int16_t': 'i',
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -208,3 +208,10 @@
assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
e = py.test.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')
+
+def test_redefine_common_type():
+ ffi = FFI()
+ ffi.cdef("typedef char FILE;")
+ assert repr(ffi.cast("FILE", 123)) == "<cdata 'char' '{'>"
+ ffi.cdef("typedef char int32_t;")
+ assert repr(ffi.cast("int32_t", 123)) == "<cdata 'char' '{'>"
More information about the pypy-commit
mailing list