Beispiel #1
0
 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))
Beispiel #2
0
 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('"', '\\"')))
Beispiel #3
0
 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))
Beispiel #4
0
 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('"', '\\"')))