Пример #1
0
def _GenerateHeaderHelper(t_pp,
                          t_ns,
                          u_ns=None,
                          private='',
                          is_extended_from_python=False):
    m = pyext.Module(f'fq.py.{private}path')
    ns = 'clif::name::'
    w = ns + 'wrapper'
    m.types = [
        types.ClassType('c::name::cpp_name',
                        t_pp,
                        w,
                        w + '_Type',
                        ns,
                        can_copy=False,
                        can_move=False,
                        can_destruct=True,
                        virtual='',
                        ns=t_ns)
    ]
    if u_ns is not None:
        m.types.append(
            types.ClassType('other::cpp_name',
                            'py.path.u',
                            w,
                            w + '_Type',
                            ns,
                            can_copy=False,
                            can_move=False,
                            can_destruct=True,
                            virtual='',
                            ns=u_ns))
    return '\n'.join(
        m.GenerateHeader('fq/py/my.clif', 'fq/my.h', {},
                         is_extended_from_python)) + '\n'
Пример #2
0
 def testUncopyableButMovableClassType(self):
     ns = 'clif::name::'
     w = ns + 'wrapper'
     t = types.ClassType('c::name::cpp_name',
                         'fq.py.path',
                         w,
                         w + '_Type',
                         ns,
                         can_copy=False,
                         can_move=True,
                         can_destruct=True,
                         virtual='')
     header = '\n'.join(t.GenHeader()) + '\n'
     self.assertMultiLineEqual(
         header,
         textwrap.dedent("""\
   // CLIF use `c::name::cpp_name` as fq.py.path
   bool Clif_PyObjAs(PyObject* input, c::name::cpp_name** output);
   bool Clif_PyObjAs(PyObject* input, std::shared_ptr<c::name::cpp_name>* output);
   bool Clif_PyObjAs(PyObject* input, std::unique_ptr<c::name::cpp_name>* output);
   PyObject* Clif_PyObjFrom(c::name::cpp_name*, py::PostConv);
   PyObject* Clif_PyObjFrom(std::shared_ptr<c::name::cpp_name>, py::PostConv);
   PyObject* Clif_PyObjFrom(std::unique_ptr<c::name::cpp_name>, py::PostConv);
   PyObject* Clif_PyObjFrom(c::name::cpp_name&&, py::PostConv);
   template<typename T>
   typename std::enable_if<std::is_same<T, c::name::cpp_name>::value>::type Clif_PyObjFrom(const c::name::cpp_name*, py::PostConv) = delete;
   template<typename T>
   typename std::enable_if<std::is_same<T, c::name::cpp_name>::value>::type Clif_PyObjFrom(const c::name::cpp_name&, py::PostConv) = delete;
 """))
Пример #3
0
    def testClass1Header(self):
        m = pyext.Module('fq.py.path', for_py3=str is not bytes)
        ns = 'clif::name::'
        w = ns + 'wrapper'
        t = types.ClassType('c::name::cpp_name',
                            'py.path',
                            w,
                            w + '_Type',
                            ns,
                            can_copy=False,
                            can_move=False,
                            can_destruct=True,
                            virtual='',
                            ns='c::name')
        m.types = [t]
        header = '\n'.join(m.GenerateHeader('fq/py/my.clif', 'fq/my.h',
                                            {})) + '\n'
        self.assertMultiLineEqual(
            header,
            textwrap.dedent("""\
      //////////////////////////////////////////////////////////////////////
      // This file was automatically generated by CLIF to run under Python %d
      // Version 0.3
      //////////////////////////////////////////////////////////////////////
      // source: fq/py/my.clif

      #include <memory>
      #include "absl/types/optional.h"
      #include "fq/my.h"
      #include "clif/python/postconv.h"

      namespace c { namespace name {
      using namespace ::clif;

      // CLIF use `c::name::cpp_name` as py.path
      bool Clif_PyObjAs(PyObject* input, c::name::cpp_name** output);
      bool Clif_PyObjAs(PyObject* input, std::shared_ptr<c::name::cpp_name>* output);
      bool Clif_PyObjAs(PyObject* input, std::unique_ptr<c::name::cpp_name>* output);
      PyObject* Clif_PyObjFrom(c::name::cpp_name*, py::PostConv);
      PyObject* Clif_PyObjFrom(std::shared_ptr<c::name::cpp_name>, py::PostConv);
      PyObject* Clif_PyObjFrom(std::unique_ptr<c::name::cpp_name>, py::PostConv);
      template<typename T>
      typename std::enable_if<std::is_same<T, c::name::cpp_name>::value>::type Clif_PyObjFrom(const c::name::cpp_name*, py::PostConv) = delete;
      template<typename T>
      typename std::enable_if<std::is_same<T, c::name::cpp_name>::value>::type Clif_PyObjFrom(const c::name::cpp_name&, py::PostConv) = delete;

      } }  // namespace c::name

      // CLIF init_module if (PyObject* m = PyImport_ImportModule("fq.py.path")) Py_DECREF(m);
      // CLIF init_module else goto err;
    """ % (3 if m.py3output else 2)))
Пример #4
0
 def WrapClass(self, c, unused_ln, cpp_namespace, unused_class_ns=''):
   """Process AST.ClassDecl c."""
   cname = Ident(c.name.cpp_name)
   pyname = c.name.native
   self.Add(Context(cname, pyname, c.name.cpp_name))
   ns = self.class_namespace
   yield ''
   yield 'namespace %s {' % ns
   virtual, has_iterator = _IsSpecialClass(c, pyname)
   if virtual:
     for s in gen.VirtualOverriderClass(
         VIRTUAL_OVERRIDER_CLASS, pyname,
         c.name.cpp_name, c.name.cpp_name+'::'+cname, c.cpp_abstract,
         Ident, vfuncs=virtual,
         pcfunc=lambda t, tm=self.typemap: postconv.Initializer(t, tm)):
       yield s
     c.bases.add().cpp_name = c.name.cpp_name
   # Flag that we're now in the nested __iter__ class.
   iter_class = (pyname == _ITER_KW)
   for s in gen.WrapperClassDef(
       WRAPPER_CLASS_NAME,
       is_iter=iter_class,
       has_iter=has_iterator,
       iter_ns=_ClassNamespace(_ITER_KW),
       cname=c.name.cpp_name,
       ctype=VIRTUAL_OVERRIDER_CLASS if virtual else c.name.cpp_name,
       enable_instance_dict=c.enable_instance_dict):
     yield s
   tracked_slot_groups = {}
   cpp_has_ext_def_ctor = False
   if iter_class:
     # Special-case nested __iter__ class.
     for s in _WrapIterSubclass(c.members, self.typemap):
       yield s
     tp_slots = {
         'tp_flags': ['Py_TPFLAGS_DEFAULT'],
         'tp_iter': 'PyObject_SelfIter',
         'tp_iternext': gen.IterNext.name}
     ctor = None
   else:
     # Normal class generator.
     if c.final:
       self.final = True
     else:
       yield ''
       yield 'static %s* ThisPtr(PyObject*);' % c.name.cpp_name
     ctor = ('DEF' if c.cpp_has_def_ctor and (not c.cpp_abstract or virtual)
             else None)
     for d in c.members:
       if d.decltype == d.FUNC:
         f = d.func
         if f.name.native == '__init__':
           if virtual:
             # Constructors are not virtual, but we mark the constructor as
             # virtual to indicate that there exist virtual functions in the
             # Clif class declaration.
             f.virtual = True
           if not f.params:
             if f.is_extend_method:
               cpp_has_ext_def_ctor = True
             else:
               # Skip generating wrapper function for unextended default
               # ctor. But wrapper function for extended default ctor is still
               # necessary.
               continue
           ctor = 'wrap%s_as___init__' % types.Mangle(cname)
         elif c.cpp_abstract and f.virtual:
           continue  # Skip calling virtual func from the abstract base class.
       for s in self.WrapDecl(d, parent_ns=cpp_namespace, class_ns=ns):
         yield s
     if virtual and not ctor:
       raise ValueError(
           'A constructor should be declared in the Clif wrapper for %s as it '
           'has virtual method declarations.' % c.name.cpp_name)
     # For Py2 slots.py relies on Py_TPFLAGS_DEFAULT being set.
     tp_slots = {'tp_flags': ['Py_TPFLAGS_DEFAULT']}
     if c.cpp_abstract:
       tp_slots['tp_flags'].append('Py_TPFLAGS_IS_ABSTRACT')
     if not c.final:
       tp_slots['tp_flags'].append('Py_TPFLAGS_BASETYPE')
     if has_iterator:
       n = _ClassNamespace(_ITER_KW)+'::'
       w = n + WRAPPER_CLASS_NAME
       # Python convention to have a type struct named FOO_Type.
       for s in gen.NewIter(_GetCppObj(), n, w, w+'_Type'):
         yield s
       tp_slots['tp_iter'] = gen.NewIter.name
     if self.properties or c.enable_instance_dict:
       yield ''
       for s in gen.GetSetDef(self.properties, c.enable_instance_dict):
         yield s
       tp_slots['tp_getset'] = gen.GetSetDef.name
     if not c.suppress_upcasts:
       for b in c.bases:
         if b.cpp_name and not b.native:
           p = b.cpp_name
           w = 'as_' + types.Mangle(p)  # pyname == cname == w
           for s in gen.CastAsCapsule(_GetCppObj(), p, w):
             yield s
           self.methods.append((w, w, NOARGS, 'Upcast to %s*' % p))
     _AppendReduceExIfNeeded(self.methods)
     if self.methods:
       for s in slots.GenSlots(self.methods, tp_slots,
                               tracked_groups=tracked_slot_groups):
         yield s
       if self.methods:  # If all methods are slots, it's empty.
         for s in gen.MethodDef(self.methods):
           yield s
         tp_slots['tp_methods'] = gen.MethodDef.name
   qualname = '.'.join(f.pyname for f in self.nested)
   tp_slots['tp_name'] = '"%s.%s"' % (self.path, qualname)
   if c.docstring:
     docstring = c.docstring.strip()
     # Escape characters for inclusion in the raw C string.
     if str is bytes:  # PY2
       docstring = docstring.encode('unicode-escape')
     docstring = docstring.replace('\n', r'\n')
     docstring = docstring.replace('"', r'\"')
     tp_slots['tp_doc'] = '"%s"' % docstring
   if c.async_dtor and c.cpp_has_trivial_dtor:
     raise ValueError('Class %s has a trivial dtor yet @async__del__ decorator'
                      % pyname)
   # Python convention to have a type struct named FOO_Type.
   # Generate wrapper Type object in wname+'_Type' static var.
   for s in gen.TypeObject(
       qualname,
       tracked_slot_groups,
       tp_slots,
       pyname,
       ctor,
       wname=WRAPPER_CLASS_NAME,
       fqclassname=c.name.cpp_name,
       abstract=c.cpp_abstract,
       iterator=_GetCppObj('iter') if iter_class else None,
       trivial_dtor=c.cpp_has_trivial_dtor,
       subst_cpp_ptr=VIRTUAL_OVERRIDER_CLASS if virtual else '',
       enable_instance_dict=c.enable_instance_dict,
       cpp_has_ext_def_ctor=cpp_has_ext_def_ctor):
     yield s
   if not iter_class:
     for s in types.GenThisPointerFunc(c.name.cpp_name, WRAPPER_CLASS_NAME,
                                       c.final):
       yield s
   yield ''
   yield '}  // namespace ' + ns
   type_dict = self.dict
   wrapns = '::'.join(f.class_namespace for f in self.nested) + '::'
   wclass = wrapns + WRAPPER_CLASS_NAME
   vclass = wrapns + VIRTUAL_OVERRIDER_CLASS
   # Python convention to have a type struct named FOO_Type.
   wtype = wclass + '_Type'
   self.DropContext()
   base, wrapped_base = _ProcessInheritance(
       c.bases, '::%s_Type' % WRAPPER_CLASS_NAME, self.namemap)
   self.types_init.append((wtype, base, wrapped_base, type_dict))
   if iter_class:
     if base:
       raise TypeError("__iter__ class can't be derived, base '%s' found"
                       % base)
   else:
     self.dict.append((pyname, types.AsPyObj(wtype)))
     self.types.append(
         types.ClassType(c.name.cpp_name, qualname, wclass, wtype, wrapns,
                         can_copy=c.cpp_copyable and not c.cpp_abstract,
                         can_move=c.cpp_movable and not c.cpp_abstract,
                         can_destruct=c.cpp_has_public_dtor,
                         virtual=vclass if virtual else '',
                         ns=cpp_namespace))