def WrapCallable(self, c, fname, retnum, line_number): """Process callable return type AST.Type c.""" assert c.HasField('callable'), ('WrapCallable called on AST that has no' ' "callable":\n' + str(c)) cname = Ident(c.callable.name.cpp_name) or fname+'_ret%d_lambda' % retnum wname = 'lambda_'+cname for i, r in enumerate(c.callable.returns): if r.type.HasField('callable'): for s in self.WrapCallable(r.type, cname, i, line_number): yield s if not c.cpp_type: assert c.callable, 'Non-callable param has empty cpp_type' c.cpp_type = 'std::function<%s>' % astutils.StdFuncParamStr(c.callable) for s in gen.FunctionCall( '', wname, doc=c.lang_type, catch=self.catch_cpp_exceptions and not c.callable.cpp_noexcept, call=['void* fp = PyCapsule_GetPointer(self, typeid(%s).name());' % c.cpp_type, 'if (fp == nullptr) return nullptr;', '(*static_cast<%s*>(fp))' % c.cpp_type], postcall_init=None, typepostconversion=self.typemap, func_ast=c.callable, lineno=line_number): yield s defname = wname + '_def' yield gen.FromFunctionDef(c.cpp_type, defname, wname, VARARGS if len(c.callable.params) else NOARGS, 'Calls '+c.cpp_type) self.types.add(types.CallableType(c.cpp_type, c.lang_type, defname))
def WrapFunc(self, f, ln, unused_ns, class_ns=''): """Process AST.FuncDecl f.""" cname = Ident(f.name.cpp_name) assert cname, 'cpp_name is empty for ' + f.name.native pyname = f.name.native.rstrip('#') if pyname.endswith('@'): ctxmgr = pyname pyname = pyname[:-1] else: ctxmgr = None if self.nested and cname.startswith('operator'): wrapper_name = 'wrap' + pyname elif pyname == '__init__': wrapper_name = 'wrap' + types.Mangle(self.name) + '_as___init__' else: wrapper_name = 'wrap' + types.Mangle(cname) if pyname != cname: wrapper_name += '_as_' + pyname if f.ignore_return_value: assert len( f.returns) < 2, ('Func with ignore_return_value has too many' ' returns (%d)' % len(f.returns)) del f.returns[:] for s in self._WrapAllCallables(f, cname, ln, class_ns, False): yield s if f.cpp_opfunction or (f.is_extend_method and not f.classmethod and not f.constructor): self_param = f.params.pop(0) else: self_param = None if ctxmgr: assert not f.classmethod, "Context manager methods can't be static" # Force context manager args API. meth = VARARGS if ctxmgr == '__exit__@' else NOARGS else: meth = VARARGS if len(f.params) else NOARGS for s in gen.FunctionCall( # Keep '@' in method name to distinguish a ctxmgr. f.name.native.rstrip('#'), wrapper_name, func_ast=f, lineno=ln, call=self._FunctionCallExpr(f, cname, pyname), doc=next(astutils.Docstring(f)), prepend_self=self_param, catch=self.catch_cpp_exceptions and not f.cpp_noexcept, postcall_init=None, typepostconversion=self.typemap): yield s if f.classmethod: meth += ' | METH_CLASS' # Keep '#' in method name to distinguish map/seq slots. self.methods.append( (f.name.native.rstrip('@'), wrapper_name, meth, '\\n'.join(astutils.Docstring(f)).replace('"', '\\"')))
def WrapOneCallable(self, c, fname, ret_or_arg, line_number, class_ns, only_pyobjas): """Process callable return or param type of AST.Type c.""" assert c.HasField('callable'), ( 'WrapOneCallable called on AST that has no' ' "callable":\n' + str(c)) cname = Ident( c.callable.name.cpp_name) or fname + '_%s_lambda' % ret_or_arg wname = 'lambda_' + cname for s in self._WrapAllCallables(c.callable, cname, line_number, class_ns, not only_pyobjas): yield s if only_pyobjas is ret_or_arg.startswith('ret'): # Clif_PyObjFrom() for this callable is not needed (only Clif_PyObjAs()). return if not c.cpp_type: assert c.callable, 'Non-callable param has empty cpp_type' c.cpp_type = 'std::function<%s>' % astutils.StdFuncParamStr( c.callable) if c.cpp_type in self.types_std_function_cpp_types: return self.types_std_function_cpp_types.add(c.cpp_type) for s in gen.FunctionCall( '', wname, doc=c.lang_type, catch=self.catch_cpp_exceptions and not c.callable.cpp_noexcept, call=[ 'void* fp = PyCapsule_GetPointer(self, typeid(%s).name());' % c.cpp_type, 'if (fp == nullptr) return nullptr;', '(*static_cast<%s*>(fp))' % c.cpp_type ], postcall_init=None, typepostconversion=self.typemap, func_ast=c.callable, lineno=line_number): yield s defname = wname + '_def' yield '' yield gen.FromFunctionDef( c.cpp_type, defname, wname, VARARGS if len(c.callable.params) else NOARGS, 'Calls ' + c.cpp_type) if class_ns: defname = class_ns + '::' + defname self.types.append(types.CallableType(c.cpp_type, c.lang_type, defname))
def WrapFunc(self, f, ln, unused_ns): """Process AST.FuncDecl f.""" cname = Ident(f.name.cpp_name) assert cname pyname = f.name.native.rstrip('#') if pyname.endswith('@'): ctxmgr = pyname pyname = pyname[:-1] else: ctxmgr = None if self.nested and cname.startswith('operator'): wrapper_name = 'wrap' + pyname elif pyname == '__init__': wrapper_name = 'wrap' + types.Mangle(self.name) + '_as___init__' else: wrapper_name = 'wrap' + types.Mangle(cname) if pyname != cname: wrapper_name += '_as_' + pyname if f.ignore_return_value: assert len( f.returns) < 2, ('Func with ignore_return_value has too many' ' returns (%d)' % len(f.returns)) del f.returns[:] for i, r in enumerate(f.returns): if r.type.HasField('callable'): for s in (self.WrapCallable(r.type, cname, i, ln)): yield s self_param = f.params.pop(0) if f.cpp_opfunction else None if ctxmgr: assert not f.classmethod, "Context manager methods can't be static" # Force context manager args API. meth = VARARGS if ctxmgr == '__exit__@' else NOARGS else: meth = VARARGS if len(f.params) else NOARGS call = f.name.cpp_name postcall = None if self.nested and not f.classmethod: cpp = 'reinterpret_cast<%s*>(self)->cpp' % self.wrapper_class_name if f.constructor: assert not f.returns, cname + ' ctor must return void' if f.virtual: ctor = VIRTUAL_OVERRIDER_CLASS postcall = '->::clif::PyObj::Init(self);' else: ctor = self.fqname if pyname == '__init__': call = '%s = ::clif::MakeShared<%s>' % (cpp, ctor) if postcall: postcall = cpp + postcall # C++ constructors do not return anything. f.cpp_void_return = True else: # additional ctors f.classmethod = True call = '::gtl::MakeUnique<%s>' % ctor # Pretend we're returning a new instance. r = f.returns.add() r.type.lang_type = self.pyname r.type.cpp_type = 'std::unique_ptr<%s>' % ctor f.cpp_void_return = False elif not f.cpp_opfunction: if self.final: call = cpp + '->' + cname else: call = [ '%s* c = ThisPtr(self);' % self.fqname, 'if (!c) return nullptr;', ] if f.virtual: call.append('c->' + self.name + '::' + cname) else: call.append('c->' + cname) for s in ( # Keep '@' in method name to distinguish ctxmgr. gen.FunctionCall(f.name.native.rstrip('#'), wrapper_name, doc=next(astutils.Docstring(f)), catch=self.catch_cpp_exceptions and not f.cpp_noexcept, call=call, postcall_init=postcall, lineno=ln, prepend_self=self_param, typepostconversion=self.typemap, func_ast=f)): yield s if f.classmethod: meth += ' | METH_CLASS' # Keep '#' in method name to distinguish map/seq slots. self.methods.append( (f.name.native.rstrip('@'), wrapper_name, meth, '\\n'.join(astutils.Docstring(f)).replace('"', '\\"')))