[pypy-commit] cffi win32-stdcall: Parse __cdecl and __stdcall in the built-in parser
arigo
noreply at buildbot.pypy.org
Tue Oct 6 13:14:47 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: win32-stdcall
Changeset: r2319:d513c1efe328
Date: 2015-10-06 13:13 +0200
http://bitbucket.org/cffi/cffi/changeset/d513c1efe328/
Log: Parse __cdecl and __stdcall in the built-in parser
diff --git a/c/parse_c_type.c b/c/parse_c_type.c
--- a/c/parse_c_type.c
+++ b/c/parse_c_type.c
@@ -40,6 +40,9 @@
TOK_UNSIGNED,
TOK_VOID,
TOK_VOLATILE,
+
+ TOK_CDECL,
+ TOK_STDCALL,
};
typedef struct {
@@ -154,6 +157,8 @@
switch (*p) {
case '_':
if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL;
+ if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL;
+ if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL;
break;
case 'c':
if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR;
@@ -225,7 +230,7 @@
type). The 'outer' argument is the index of the opcode outside
this "sequel".
*/
- int check_for_grouping;
+ int check_for_grouping, abi=0;
_cffi_opcode_t result, *p_current;
header:
@@ -242,6 +247,12 @@
/* ignored for now */
next_token(tok);
goto header;
+ case TOK_CDECL:
+ case TOK_STDCALL:
+ /* must be in a function; checked below */
+ abi = tok->kind;
+ next_token(tok);
+ goto header;
default:
break;
}
@@ -258,6 +269,11 @@
while (tok->kind == TOK_OPEN_PAREN) {
next_token(tok);
+ if (tok->kind == TOK_CDECL || tok->kind == TOK_STDCALL) {
+ abi = tok->kind;
+ next_token(tok);
+ }
+
if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR ||
tok->kind == TOK_CONST ||
tok->kind == TOK_VOLATILE ||
@@ -275,7 +291,14 @@
}
else {
/* function type */
- int arg_total, base_index, arg_next, has_ellipsis=0;
+ int arg_total, base_index, arg_next, flags=0;
+
+ if (abi == TOK_STDCALL) {
+ flags = 2;
+ /* note that an ellipsis below will overwrite this flags,
+ which is the goal: variadic functions are always cdecl */
+ }
+ abi = 0;
if (tok->kind == TOK_VOID && get_following_char(tok) == ')') {
next_token(tok);
@@ -304,7 +327,7 @@
_cffi_opcode_t oarg;
if (tok->kind == TOK_DOTDOTDOT) {
- has_ellipsis = 1;
+ flags = 1; /* ellipsis */
next_token(tok);
break;
}
@@ -328,8 +351,7 @@
next_token(tok);
}
}
- tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END,
- has_ellipsis);
+ tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END, flags);
}
if (tok->kind != TOK_CLOSE_PAREN)
@@ -337,6 +359,9 @@
next_token(tok);
}
+ if (abi != 0)
+ return parse_error(tok, "expected '('");
+
while (tok->kind == TOK_OPEN_BRACKET) {
*p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index);
p_current = tok->output + tok->output_index;
diff --git a/testing/cffi1/test_parse_c_type.py b/testing/cffi1/test_parse_c_type.py
--- a/testing/cffi1/test_parse_c_type.py
+++ b/testing/cffi1/test_parse_c_type.py
@@ -341,3 +341,17 @@
# not supported (really obscure):
# "char[+5]"
# "char['A']"
+
+def test_stdcall_cdecl():
+ assert parse("int __stdcall(int)") == [Prim(lib._CFFI_PRIM_INT),
+ '->', Func(0), NoOp(4), FuncEnd(2),
+ Prim(lib._CFFI_PRIM_INT)]
+ assert parse("int __stdcall func(int)") == parse("int __stdcall(int)")
+ assert parse("int (__stdcall *)()") == [Prim(lib._CFFI_PRIM_INT),
+ NoOp(3), '->', Pointer(1),
+ Func(0), FuncEnd(2), 0]
+ assert parse("int (__stdcall *p)()") == parse("int (__stdcall*)()")
+ parse_error("__stdcall int", "identifier expected", 0)
+ parse_error("__cdecl int", "identifier expected", 0)
+ parse_error("int __stdcall", "expected '('", 13)
+ parse_error("int __cdecl", "expected '('", 11)
diff --git a/testing/cffi1/test_realize_c_type.py b/testing/cffi1/test_realize_c_type.py
--- a/testing/cffi1/test_realize_c_type.py
+++ b/testing/cffi1/test_realize_c_type.py
@@ -1,4 +1,4 @@
-import py
+import py, sys
from cffi import cffi_opcode
@@ -46,3 +46,29 @@
def test_all_primitives():
for name in cffi_opcode.PRIMITIVE_TO_INDEX:
check(name, name)
+
+
+def check_func(input, expected_output=None):
+ import _cffi_backend
+ ffi = _cffi_backend.FFI()
+ ct = ffi.typeof(ffi.callback(input, lambda: None))
+ assert isinstance(ct, ffi.CType)
+ if sys.platform != 'win32':
+ expected_output = expected_output.replace('__stdcall *', '*')
+ assert ct.cname == expected_output
+
+def test_funcptr_stdcall():
+ check_func("int(int)", "int(*)(int)")
+ check_func("int foobar(int)", "int(*)(int)")
+ check_func("int __stdcall(int)", "int(__stdcall *)(int)")
+ check_func("int __stdcall foobar(int)", "int(__stdcall *)(int)")
+ check_func("void __cdecl(void)", "void(*)()")
+ check_func("void __cdecl foobar(void)", "void(*)()")
+ check_func("void __stdcall(void)", "void(__stdcall *)()")
+ check_func("void __stdcall foobar(long, short)",
+ "void(__stdcall *)(long, short)")
+ check_func("void(void __cdecl(void), void __stdcall(void))",
+ "void(*)(void(*)(), void(__stdcall *)())")
+
+def test_variadic_overrides_stdcall():
+ check("void (__stdcall*)(int, ...)", "void(*)(int, ...)")
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -1200,25 +1200,6 @@
lib = ffi.verify('#include <math.h>', libraries=lib_m)
assert lib.sin(1.23) == math.sin(1.23)
-def test_callback_calling_convention():
- py.test.skip("later")
- if sys.platform != 'win32':
- py.test.skip("Windows only")
- ffi = FFI()
- ffi.cdef("""
- int call1(int(*__cdecl cb)(int));
- int call2(int(*__stdcall cb)(int));
- """)
- lib = ffi.verify("""
- int call1(int(*__cdecl cb)(int)) {
- return cb(42) + 1;
- }
- int call2(int(*__stdcall cb)(int)) {
- return cb(-42) - 6;
- }
- """)
- xxx
-
def test_opaque_integer_as_function_result():
#import platform
#if platform.machine().startswith('sparc'):
More information about the pypy-commit
mailing list