Skip to content

Commit 573bd69

Browse files
committed
Merge branch 'misl6-fix/args-no-frame'
2 parents dccb07c + 1143b49 commit 573bd69

File tree

3 files changed

+37
-53
lines changed

3 files changed

+37
-53
lines changed

pyobjus/common.pxi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ cdef extern from "objc/runtime.h":
9393
const_char_ptr sel_getName(SEL)
9494

9595
SEL method_getName(Method)
96-
const_char_ptr method_getTypeEncoding(Method)
96+
unsigned int method_getNumberOfArguments(Method)
9797
const_char_ptr method_copyArgumentType(Method method, int)
98+
const_char_ptr method_copyReturnType(Method)
9899
objc_method_description* method_getDescription(Method m)
99100

100101
Class object_getClass(id obj)

pyobjus/pyobjus.pyx

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ def convert_return_value(retval, clsname, methodname):
189189

190190
cdef class ObjcMethod(object):
191191
cdef bytes name
192-
cdef bytes signature
193192
cdef int is_static
194193
cdef object signature_return
195194
cdef object signature_current_args
@@ -211,7 +210,7 @@ cdef class ObjcMethod(object):
211210
cdef ffi_type **f_arg_types
212211
cdef object objc_name
213212

214-
def __cinit__(self, signature, objc_name, **kwargs):
213+
def __cinit__(self, objc_name, signature_args, signature_return, **kwargs):
215214
self.is_ready = 0
216215
self.f_result_type = NULL
217216
self.f_arg_types = NULL
@@ -238,10 +237,12 @@ cdef class ObjcMethod(object):
238237
#self.f_result_type = NULL
239238
# TODO: Memory management
240239

241-
def __init__(self, bytes signature, bytes objc_name, **kwargs):
240+
def __init__(self, bytes objc_name, signature_args, signature_return, **kwargs):
242241
super(ObjcMethod, self).__init__()
243-
self.signature = <bytes>signature
244-
self.signature_return, self.signature_args = parse_signature(signature)
242+
243+
self.signature_args = [clean_type_specifier(sign_arg) for sign_arg in signature_args]
244+
self.signature_return = clean_type_specifier(signature_return)
245+
245246
self.is_static = kwargs.get('static', False)
246247
self.name = kwargs.get('name')
247248
self.objc_name = objc_name
@@ -272,8 +273,8 @@ cdef class ObjcMethod(object):
272273
else:
273274
self.name = self.objc_name
274275

275-
if self.signature_return[0].startswith((b'(', b'{')):
276-
sig = self.signature_return[0]
276+
if self.signature_return.startswith((b'(', b'{')):
277+
sig = self.signature_return
277278
self.return_type = sig[1:-1].split(b'=', 1)
278279

279280
self.selector = sel_registerName(<bytes>self.name)
@@ -290,12 +291,12 @@ cdef class ObjcMethod(object):
290291
dprint('signature: {}'.format(signature_args))
291292

292293
# resolve f_result_type
293-
if self.signature_return[0].startswith(b'('):
294+
if self.signature_return.startswith(b'('):
294295
self.f_result_type = type_encoding_to_ffitype(
295-
self.signature_return[0], str_in_union=True)
296+
self.signature_return, str_in_union=True)
296297
else:
297298
self.f_result_type = type_encoding_to_ffitype(
298-
self.signature_return[0])
299+
self.signature_return)
299300

300301
# casting is needed here because otherwise we will get warning at compile
301302
cdef unsigned int num_args = <unsigned int>len(signature_args)
@@ -313,12 +314,12 @@ cdef class ObjcMethod(object):
313314
# populate f_args_type array for FFI prep
314315
cdef int index = 0
315316
for arg in signature_args:
316-
if arg[0].startswith(b'('):
317+
if arg.startswith(b'('):
317318
raise ObjcException(
318319
'Currently passing unions as arguments by '
319320
'value is not supported in pyobjus!')
320321
dprint('argument ==>', arg, len(signature_args))
321-
self.f_arg_types[index] = type_encoding_to_ffitype(arg[0])
322+
self.f_arg_types[index] = type_encoding_to_ffitype(arg)
322323
index = index + 1
323324

324325
# FFI PREP
@@ -360,7 +361,6 @@ cdef class ObjcMethod(object):
360361
cdef int index
361362
cdef size_t size
362363
cdef ObjcClassInstance arg_objcclass
363-
cdef size_t result_size = <size_t>int(self.signature_return[1])
364364

365365
# check that we have at least the same number of arguments as the
366366
# signature want (having more than expected could signify that the called
@@ -405,7 +405,7 @@ cdef class ObjcMethod(object):
405405
sig_index = -1
406406
signature_args.append(signature_args[-1])
407407

408-
sig, offset, attr = sig_full = signature_args[sig_index]
408+
sig = signature_args[sig_index]
409409
arg_size = type_encoding_to_ffitype(sig).size
410410

411411
# we already know the ffitype/size being used
@@ -435,7 +435,7 @@ cdef class ObjcMethod(object):
435435
if res_ptr == NULL:
436436
raise MemoryError('Unable to allocate res_ptr')
437437

438-
if not self.signature_return[0].startswith((b'(', b'{')):
438+
if not self.signature_return.startswith((b'(', b'{')):
439439
ffi_call(&self.f_cif, <void(*)() noexcept><id(*)(id, SEL)>objc_msgSend, res_ptr, f_args)
440440

441441
else:
@@ -461,7 +461,7 @@ cdef class ObjcMethod(object):
461461
size_ret = ctypes.sizeof(obj_ret)
462462

463463
stret = False
464-
if self.signature_return[0].startswith((b'{', b'(')) and size_ret > 16:
464+
if self.signature_return.startswith((b'{', b'(')) and size_ret > 16:
465465
stret = True
466466

467467
if stret and MACOS_HAVE_OBJMSGSEND_STRET:
@@ -490,8 +490,8 @@ cdef class ObjcMethod(object):
490490
cdef ObjcClassInstance cret
491491
cdef bytes bret
492492

493-
sig = self.signature_return[0]
494-
dprint("return signature", self.signature_return[0], of_type="i")
493+
sig = self.signature_return
494+
dprint("return signature", self.signature_return, of_type="i")
495495

496496
if sig == b'@':
497497
ret_id = (<id>res_ptr[0])
@@ -529,10 +529,13 @@ cdef objc_method_to_py(Method method, main_cls_name, static=True):
529529
'''
530530

531531
cdef char* method_name = <char*>sel_getName(method_getName(method))
532-
cdef char* method_args = <char*>method_getTypeEncoding(method)
532+
cdef unsigned int method_args_len = method_getNumberOfArguments(method)
533+
cdef char* method_return_type = method_copyReturnType(method)
534+
cdef list method_args_types = [method_copyArgumentType(method, i) for i in range(method_args_len)]
535+
533536
cdef basestring py_name = (<bytes>method_name).replace(b":", b"_").decode("utf-8")
534537

535-
return py_name, ObjcMethod(<bytes>method_args, method_name, static=static, main_cls_name=main_cls_name)
538+
return py_name, ObjcMethod(method_name, method_args_types, method_return_type, static=static, main_cls_name=main_cls_name)
536539

537540
cdef class_get_methods(Class cls, static=False, main_cls_name=None):
538541
cdef unsigned int index, num_methods
@@ -605,7 +608,11 @@ cdef get_class_method(Class cls, char *name):
605608
ObjcMethod instance
606609
'''
607610
cdef Method m_cls = class_getClassMethod(cls, sel_registerName(name))
608-
return ObjcMethod(<bytes><char*>method_getTypeEncoding(m_cls), name, static=True, \
611+
cdef unsigned int method_args_len = method_getNumberOfArguments(m_cls)
612+
cdef char* method_return_type = method_copyReturnType(m_cls)
613+
cdef list method_args_types = [method_copyArgumentType(m_cls, i) for i in range(method_args_len)]
614+
615+
return ObjcMethod(name, method_args_types, method_return_type, static=True, \
609616
main_cls_name=class_getName(cls))
610617

611618
cdef resolve_super_class_methods(Class cls, instance_methods=True):

pyobjus/type_enc.pxi

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,12 @@
1-
def seperate_encoding(sig):
2-
c = sig[0][:1]
3-
4-
if c in b'rnNoORV':
5-
sig = (sig[0][1:], sig[1], c)
6-
else:
7-
sig = (sig[0], sig[1], None)
1+
def clean_type_specifier(sig):
2+
"""
3+
Clean up the type specifier for a function signature.
4+
See: https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Type-encoding.html
5+
"""
6+
if sig[:1] in b'rnNoORV':
7+
return sig[1:]
88
return sig
99

10-
11-
def parse_signature(bytes signature):
12-
parts = re.split(b'(\d+)', signature)[:-1]
13-
signature_return = seperate_encoding(parts[0:2])
14-
parts = parts[2:]
15-
signature_args = [seperate_encoding(x) for x in zip(parts[0::2], parts[1::2])]
16-
17-
# reassembly for array
18-
if b'[' in signature:
19-
tmp_sig = []
20-
arr_sig = b''
21-
for item in signature_args:
22-
if item[0].startswith(b'['):
23-
arr_sig += item[0] + item[1]
24-
elif item[0].endswith(b']'):
25-
arr_sig += item[0]
26-
tmp_sig.append((arr_sig, item[1], item[2]))
27-
else:
28-
tmp_sig.append(item)
29-
signature_args = tmp_sig
30-
31-
return signature_return, signature_args
32-
33-
3410
def signature_types_to_list(type_encoding):
3511
type_enc_list = []
3612
curvy_brace_count = 0

0 commit comments

Comments
 (0)