Esempio n. 1
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('"', '\\"')))
Esempio n. 2
0
    def testMangleEscapedCharLiteral(self):
        # Octal escapes.
        self.assertEqual(types.Mangle(r"A<'\0', '\000', '\5', '\777'>"),
                         'A_c0__c0__c5__c511_')

        # Hexadecimal escapes.
        self.assertEqual(types.Mangle(r"A<'\x00', '\xff', '\xFF', '\xA0'>"),
                         'A_c0__c255__c255__c160_')

        # Unicode escapes.
        self.assertEqual(
            types.Mangle(r"A<'\u0000', '\u0001', '\u1000', '\u9999'>"),
            'A_c0__c1__c4096__c39321_')
        self.assertEqual(types.Mangle(r"A<'\U00000000', '\U00109999'>"),
                         'A_c0__c1087897_')

        # ASCII control code escapes.
        self.assertEqual(
            types.Mangle(r"A<'\a', '\b', '\f', '\n', '\r', '\t', '\v'>"),
            'A_c7__c8__c12__c10__c13__c9__c11_')

        # Other low-ASCII escapes.
        self.assertEqual(types.Mangle("A<'\\'', '\\\"', '\\\\'>"),
                         'A_c39__c34__c92_')
Esempio n. 3
0
 def testMangle(self):
     self.assertEqual(types.Mangle('::A<B*, const C&>'),
                      'A_B_ptr_constC_ref')
     self.assertEqual(types.Mangle('::A<B::C>'), 'A_B_C')
     self.assertEqual(types.Mangle('Abc'), 'Abc')
     self.assertEqual(types.Mangle('Abc::D'), 'Abc_D')
     self.assertEqual(types.Mangle('Abc<D>'), 'Abc_D')
     self.assertEqual(types.Mangle('Abc<D>&&'), 'Abc_D__rref')
     self.assertEqual(types.Mangle('Abc<D::E>'), 'Abc_D_E')
     self.assertEqual(types.Mangle('Abc<D *> *'), 'Abc_D_ptr__ptr')
     self.assertEqual(types.Mangle('Abc<const D *> *'),
                      'Abc_constD_ptr__ptr')
     self.assertEqual(types.Mangle('Abc const&'), 'Abcconst_ref')
     self.assertEqual(types.Mangle('A<B, -1>'), 'A_B__1')
     self.assertEqual(types.Mangle("A<B, 'a'>"), 'A_B_c97_')
Esempio n. 4
0
File: pyext.py Progetto: google/clif
 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))
Esempio n. 5
0
File: pyext.py Progetto: google/clif
  def WrapVar(self, v, unused_ln, unused_ns, unused_class_ns=''):
    """Process AST.VarDecl v."""
    assert self.nested, 'C++ global vars not allowed, use const'
    assert '::' not in v.name.cpp_name
    vname = v.name.cpp_name
    ctype = v.type.cpp_type
    if v.cpp_set and not v.cpp_get:
      raise NameError('Property %s has setter, but no getter' % v.name.native)
    getter = 'get_' + vname
    setter = 'set_' + vname
    if self.final:
      base = None
      cobj = _GetCppObj() + '->'
    else:
      base = 'auto cpp = ThisPtr(self); if (!cpp) '
      cobj = 'cpp->'
    is_property = False
    if v.cpp_get.name.cpp_name:
      # It's a property var (with cpp only `getter`, `setter`).
      assert not v.cpp_get.name.native
      is_property = True
      if v.cpp_get.classmethod or v.cpp_set.classmethod:
        raise ValueError('Static properties not supported')
      if v.cpp_set.name.cpp_name:
        assert not v.cpp_set.name.native
      else:
        setter = 'nullptr'
      vname = Ident(v.cpp_get.name.cpp_name) + '()'
    nested_container = not is_property
    cvar = cobj + vname
    getval = cvar
    setval = (cobj + Ident(v.cpp_set.name.cpp_name)
              if v.cpp_set.name.cpp_name else '')
    if v.is_extend_variable:
      orig_getter_name = v.cpp_get.name.cpp_name.split(
          ast_manipulations.EXTEND_INFIX)[-1]
      cname = Ident(v.cpp_get.name.cpp_name)
      wrapper_name = 'wrap' + types.Mangle(cname)
      getval = wrapper_name + '_as_' + orig_getter_name + '(self)'

      if v.cpp_set:
        setval = v.cpp_set.name.cpp_name
    unproperty = False
    if v.cpp_get.name.native:
      # It's an unproperty var (@getter pyname / @setter pyname).
      assert not v.cpp_get.name.cpp_name
      unproperty = True
      nested_container = False
      self.methods.append((v.cpp_get.name.native, getter,
                           NOARGS, '%s()->%s  C++ %s.%s getter' %
                           (v.cpp_get.name.native, v.type.lang_type,
                            self.name, v.name.cpp_name)))
      if v.cpp_set.name.native:
        assert not v.cpp_set.name.cpp_name
        self.methods.append((v.cpp_set.name.native, setter,
                             'METH_O', '%s(%s)  C++ %s.%s setter' %
                             (v.cpp_set.name.native, v.type.lang_type,
                              self.name, v.name.cpp_name)))
      else:
        setter = 'nullptr'
    else:
      self.properties.append((v.name.native, getter, setter, 'C++ %s %s.%s' % (
          ctype, self.CppName(), vname)))
      if not v.type.cpp_abstract and not ctype.startswith('::std::shared_ptr'):
        if v.type.cpp_raw_pointer or ctype.startswith('::std::unique_ptr'):
          getval = '*' + cvar
          nested_container = False
        elif nested_container and v.type.cpp_toptr_conversion:
          # For a nested container we'll try to return it (we use
          # cpp_toptr_conversion as an indicator for a custom container).
          getval = '::clif::MakeStdShared(%s, &%s)' % (_GetCppObj(), cvar)
    for s in gen.VarGetter(getter, unproperty, base, getval,
                           postconv.Initializer(v.type, self.typemap),
                           is_extend=v.is_extend_variable):
      yield s
    if setter != 'nullptr':
      for s in gen.VarSetter(
          setter,
          unproperty,
          base,
          cvar,
          v,
          setval,
          as_str='PyUnicode_AsUTF8',
          is_extend=v.is_extend_variable):
        yield s