mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
- If you export a derived class without exporting its base classes, the derived class will explicitly export the bases's methods and attributes. Before, if you were interested in the bases's methods, you had to export the base classes too.
- Added a new function, no_override. When a member function is specified as "no_override", no virtual wrappers are generated for it, improving performance and letting the code more clean. - There was a bug in which the policy of virtual member functions was being ignored (patch by Roman Sulzhyk). [SVN r18814]
This commit is contained in:
18
pyste/NEWS
18
pyste/NEWS
@@ -1,3 +1,21 @@
|
||||
16 June 2003
|
||||
Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours
|
||||
have changed:
|
||||
|
||||
- If you export a derived class without exporting its base classes, the derived
|
||||
class will explicitly export the bases's methods and attributes. Before, if
|
||||
you were interested in the bases's methods, you had to export the base
|
||||
classes too.
|
||||
|
||||
- Added a new function, no_override. When a member function is specified as
|
||||
"no_override", no virtual wrappers are generated for it, improving
|
||||
performance and letting the code more clean.
|
||||
|
||||
- There was a bug in which the policy of virtual member functions was being
|
||||
ignored (patch by Roman Sulzhyk).
|
||||
|
||||
Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig.
|
||||
|
||||
4 June 2003
|
||||
Major improvements in memory usage.
|
||||
|
||||
|
||||
@@ -165,8 +165,8 @@ invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
cpp file with Boost.Python code, with all the classes and functions exported.
|
||||
|
||||
Besides declaring the classes and functions, the user has a number of other
|
||||
options, like renaming classes and methods, excluding methods and attributes,
|
||||
and so on.
|
||||
options, like renaming e excluding classes and member functionis. Those are
|
||||
explained later on.
|
||||
|
||||
[h2 Basics]
|
||||
|
||||
@@ -200,7 +200,7 @@ That will expose the class, the free function and the enum found in [^hello.h].
|
||||
|
||||
[page:1 Renaming and Excluding]
|
||||
|
||||
You can easily rename functions, classes, methods, attributes, etc. Just use the
|
||||
You can easily rename functions, classes, member functions, attributes, etc. Just use the
|
||||
function [^rename], like this:
|
||||
|
||||
World = Class("World", "hello.h")
|
||||
@@ -208,7 +208,7 @@ function [^rename], like this:
|
||||
show = Function("choice", "hello.h")
|
||||
rename(show, "Show")
|
||||
|
||||
You can rename methods and attributes using this syntax:
|
||||
You can rename member functions and attributes using this syntax:
|
||||
|
||||
rename(World.greet, "Greet")
|
||||
rename(World.set, "Set")
|
||||
@@ -216,7 +216,7 @@ You can rename methods and attributes using this syntax:
|
||||
rename(choice.red, "Red")
|
||||
rename(choice.blue, "Blue")
|
||||
|
||||
You can exclude functions, classes, methods, attributes, etc, in the same way,
|
||||
You can exclude functions, classes, member functions, attributes, etc, in the same way,
|
||||
with the function [^exclude]:
|
||||
|
||||
exclude(World.greet)
|
||||
@@ -231,12 +231,25 @@ To access the operators of a class, access the member [^operator] like this
|
||||
|
||||
The string inside the brackets is the same as the name of the operator in C++.[br]
|
||||
|
||||
[h2 Virtual Member Functions]
|
||||
|
||||
Pyste automatically generates wrappers for virtual member functions, but you
|
||||
may want to disable this behaviour (for performance reasons, or to let the code
|
||||
more clean) if you do not plan to override the functions in Python. To do
|
||||
this, use the function [^no_override]:
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
no_override(C.foo) # C::foo is a virtual member function
|
||||
|
||||
No wrapper code will be generated for the virtual member function C::foo that
|
||||
way.
|
||||
|
||||
[page:1 Policies]
|
||||
|
||||
Even thought Pyste can identify various elements in the C++ code, like virtual
|
||||
methods, attributes, and so on, one thing that it can't do is to guess the
|
||||
semantics of functions that return pointers or references. In this case, the
|
||||
user must manually specify the policy. Policies are explained in the
|
||||
member functions, attributes, and so on, one thing that it can't do is to
|
||||
guess the semantics of functions that return pointers or references. In this
|
||||
case, the user must manually specify the policy. Policies are explained in the
|
||||
[@../../doc/tutorial/doc/call_policies.html tutorial].
|
||||
|
||||
The policies in Pyste are named exactly as in Boost.Python, only the syntax is
|
||||
@@ -248,22 +261,23 @@ becomes in Pyste:
|
||||
|
||||
return_internal_reference(1, with_custodian_and_ward(1, 2))
|
||||
|
||||
The user can specify policies for functions and methods with the [^set_policy]
|
||||
function:
|
||||
The user can specify policies for functions and virtual member functions with
|
||||
the [^set_policy] function:
|
||||
|
||||
set_policy(f, return_internal_reference())
|
||||
set_policy(C.foo, return_value_policy(manage_new_object))
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] [*What if a function or method needs a policy and the user
|
||||
doesn't set one?][br][br] If a function/method needs a policy and one was not
|
||||
set, Pyste will issue a error. The user should then go in the interface file
|
||||
and set the policy for it, otherwise the generated cpp won't compile.
|
||||
[$theme/note.gif] [*What if a function or member function needs a policy and
|
||||
the user doesn't set one?][br][br] If a function needs a policy and one
|
||||
was not set, Pyste will issue a error. The user should then go in the
|
||||
interface file and set the policy for it, otherwise the generated cpp won't
|
||||
compile.
|
||||
]
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]
|
||||
Note that, for functions/methods that return [^const T&], the policy
|
||||
Note that, for functions that return [^const T&], the policy
|
||||
[^return_value_policy<copy_const_reference>()] wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
@@ -371,9 +385,9 @@ You can optionally declare the function in the interface file itself:
|
||||
names = Function("names", "test.h")
|
||||
set_wrapper(names, names_wrapper)
|
||||
|
||||
The same mechanism can be used with methods too. Just remember that the first
|
||||
parameter of wrappers for methods is a pointer to the class, like in
|
||||
Boost.Python:
|
||||
The same mechanism can be used with member functions too. Just remember that
|
||||
the first parameter of wrappers for member functions is a pointer to the
|
||||
class, as in:
|
||||
|
||||
struct C
|
||||
{
|
||||
@@ -394,7 +408,7 @@ And then in the interface file:
|
||||
[$theme/note.gif]Even though Boost.Python accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a [*pointer]. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual method.
|
||||
code to compile when you set a wrapper for a virtual member function.
|
||||
]
|
||||
|
||||
[page:1 Exporting An Entire Header]
|
||||
@@ -479,7 +493,8 @@ functions, and export those.
|
||||
|
||||
[page:1 Adding New Methods]
|
||||
|
||||
Suppose that you want to add a function to a class, turning it into a method:
|
||||
Suppose that you want to add a function to a class, turning it into a member
|
||||
function:
|
||||
|
||||
struct World
|
||||
{
|
||||
@@ -492,14 +507,14 @@ Suppose that you want to add a function to a class, turning it into a method:
|
||||
return w.msg;
|
||||
}
|
||||
|
||||
Here, we want to make [^greet] work as a method of the class [^World]. We do
|
||||
Here, we want to make [^greet] work as a member function of the class [^World]. We do
|
||||
that using the [^add_method] construct:
|
||||
|
||||
W = Class("World", "hello.h")
|
||||
add_method(W, "greet")
|
||||
|
||||
Notice also that then you can rename it, set its policy, just like a regular
|
||||
method:
|
||||
member function:
|
||||
|
||||
rename(W.greet, 'Greet')
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from policies import *
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
from EnumExporter import EnumExporter
|
||||
from utils import makeid, enumerate
|
||||
from copy import deepcopy
|
||||
import copy
|
||||
import exporterutils
|
||||
import re
|
||||
|
||||
@@ -66,20 +66,16 @@ class ClassExporter(Exporter):
|
||||
self.info.rename = decl.name
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.public_members = \
|
||||
[x for x in self.class_.members if x.visibility == Scope.public]
|
||||
self.class_ = copy.deepcopy(self.class_)
|
||||
|
||||
|
||||
|
||||
def ClassBases(self):
|
||||
bases = []
|
||||
def GetBases(class_):
|
||||
this_bases = [self.GetDeclaration(x.name) for x in class_.bases]
|
||||
bases.extend(this_bases)
|
||||
for base in this_bases:
|
||||
GetBases(base)
|
||||
|
||||
GetBases(self.class_)
|
||||
return bases
|
||||
all_bases = []
|
||||
for level in self.class_.hierarchy:
|
||||
for base in level:
|
||||
all_bases.append(base)
|
||||
return [self.GetDeclaration(x.name) for x in all_bases]
|
||||
|
||||
|
||||
def Order(self):
|
||||
@@ -91,6 +87,8 @@ class ClassExporter(Exporter):
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
self.InheritMethods(exported_names)
|
||||
self.MakeNonVirtual()
|
||||
if not self.info.exclude:
|
||||
self.CheckIsForwardDeclared()
|
||||
self.CheckForwardDeclarations()
|
||||
@@ -98,8 +96,8 @@ class ClassExporter(Exporter):
|
||||
self.ExportBases(exported_names)
|
||||
self.ExportConstructors()
|
||||
self.ExportVariables()
|
||||
self.ExportMethods()
|
||||
self.ExportVirtualMethods()
|
||||
self.ExportMethods()
|
||||
self.ExportOperators()
|
||||
self.ExportNestedClasses(exported_names)
|
||||
self.ExportNestedEnums()
|
||||
@@ -108,10 +106,38 @@ class ClassExporter(Exporter):
|
||||
self.Write(codeunit)
|
||||
|
||||
|
||||
def InheritMethods(self, exported_names):
|
||||
'''Go up in the class hierarchy looking for classes that were not
|
||||
exported yet, and then add their public members to this classes
|
||||
members, as if they were members of this class. This allows the user to
|
||||
just export one type and automatically get all the methods from the
|
||||
base classes.
|
||||
'''
|
||||
valid_members = (Method, ClassVariable, NestedClass, ClassOperator,
|
||||
ConverterOperator, ClassEnumeration)
|
||||
for level in self.class_.hierarchy:
|
||||
level_exported = False
|
||||
for base in level:
|
||||
base = self.GetDeclaration(base.name)
|
||||
if base.FullName() not in exported_names:
|
||||
for member in base.members:
|
||||
if type(member) in valid_members:
|
||||
member = copy.deepcopy(member)
|
||||
#if type(member) not in (ClassVariable,:
|
||||
# member.class_ = self.class_.FullName()
|
||||
self.class_.members.append(member)
|
||||
else:
|
||||
level_exported = True
|
||||
if level_exported:
|
||||
break
|
||||
self.public_members = \
|
||||
[x for x in self.class_.members if x.visibility == Scope.public]
|
||||
|
||||
def CheckIsForwardDeclared(self):
|
||||
if self.class_.incomplete:
|
||||
print "--> Error: Class %s is forward declared! " \
|
||||
"Please use the header with its complete definition." % self.class_.FullName()
|
||||
"Please use the header with its complete definition." \
|
||||
% self.class_.FullName()
|
||||
print
|
||||
|
||||
|
||||
@@ -191,15 +217,16 @@ class ClassExporter(Exporter):
|
||||
|
||||
def ExportBases(self, exported_names):
|
||||
'Expose the bases of the class into the template section'
|
||||
bases = self.class_.bases
|
||||
bases_list = []
|
||||
for base in bases:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
bases_list.append(base.name)
|
||||
if bases_list:
|
||||
code = namespaces.python + 'bases< %s > ' % \
|
||||
(', '.join(bases_list))
|
||||
self.Add('template', code)
|
||||
hierarchy = self.class_.hierarchy
|
||||
for level in hierarchy:
|
||||
exported = []
|
||||
for base in level:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
exported.append(base.name)
|
||||
if exported:
|
||||
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
|
||||
self.Add('template', code)
|
||||
return
|
||||
|
||||
|
||||
def ExportConstructors(self):
|
||||
@@ -374,6 +401,14 @@ class ClassExporter(Exporter):
|
||||
self.Add('declaration', wrapper.code)
|
||||
|
||||
|
||||
def MakeNonVirtual(self):
|
||||
'''Make all methods that the user indicated to no_override no more virtual, delegating their
|
||||
export to the ExportMethods routine'''
|
||||
for member in self.class_.members:
|
||||
if type(member) == Method and member.virtual:
|
||||
member.virtual = not self.info[member.name].no_override
|
||||
|
||||
|
||||
def ExportVirtualMethods(self):
|
||||
# check if this class has any virtual methods
|
||||
has_virtual_methods = False
|
||||
@@ -565,7 +600,6 @@ class ClassExporter(Exporter):
|
||||
nested_info.include = self.info.include
|
||||
nested_info.name = nested_class.FullName()
|
||||
exporter = ClassExporter(nested_info)
|
||||
self.declarations.append(nested_class)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
@@ -579,7 +613,6 @@ class ClassExporter(Exporter):
|
||||
enum_info.include = self.info.include
|
||||
enum_info.name = enum.FullName()
|
||||
exporter = EnumExporter(enum_info)
|
||||
self.declarations.append(enum)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, None)
|
||||
@@ -746,12 +779,17 @@ class _VirtualWrapperGenerator(object):
|
||||
else:
|
||||
pointer = method.PointerDeclaration()
|
||||
|
||||
# Add policy to overloaded methods also
|
||||
policy = self.info[method.name].policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
|
||||
# generate the defs
|
||||
definitions = []
|
||||
# basic def
|
||||
definitions.append('.def("%s", %s, %s)' % (rename, pointer, default_pointers[-1]))
|
||||
definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy))
|
||||
for default_pointer in default_pointers[:-1]:
|
||||
definitions.append('.def("%s", %s)' % (rename, default_pointer))
|
||||
definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy))
|
||||
return definitions
|
||||
|
||||
|
||||
@@ -766,7 +804,9 @@ class _VirtualWrapperGenerator(object):
|
||||
This method creates the instance variable self.virtual_methods.
|
||||
'''
|
||||
def IsVirtual(m):
|
||||
return type(m) is Method and m.virtual and m.visibility != Scope.private
|
||||
return type(m) is Method and \
|
||||
m.virtual and \
|
||||
m.visibility != Scope.private
|
||||
|
||||
all_methods = [x for x in self.class_.members if IsVirtual(x)]
|
||||
for base in self.bases:
|
||||
|
||||
@@ -64,7 +64,7 @@ class Exporter:
|
||||
|
||||
def GetDeclaration(self, fullname):
|
||||
decls = self.GetDeclarations(fullname)
|
||||
assert len(decls) == 1
|
||||
#assert len(decls) == 1
|
||||
return decls[0]
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from declarations import *
|
||||
from elementtree.ElementTree import ElementTree
|
||||
from xml.parsers.expat import ExpatError
|
||||
from copy import deepcopy
|
||||
from utils import enumerate
|
||||
|
||||
|
||||
class InvalidXMLError(Exception): pass
|
||||
@@ -199,14 +200,18 @@ class GCCXMLParser(object):
|
||||
self.ParseFunction(id, element, Operator)
|
||||
|
||||
|
||||
def GetBases(self, bases):
|
||||
'Parses the string "bases" from the xml into a list of Base instances.'
|
||||
def GetHierarchy(self, bases):
|
||||
'''Parses the string "bases" from the xml into a list of tuples of Base
|
||||
instances. The first tuple is the most direct inheritance, and then it
|
||||
goes up in the hierarchy.
|
||||
'''
|
||||
|
||||
if bases is None:
|
||||
return []
|
||||
bases = bases.split()
|
||||
baseobjs = []
|
||||
for base in bases:
|
||||
base_names = bases.split()
|
||||
this_level = []
|
||||
next_levels = []
|
||||
for base in base_names:
|
||||
# get the visibility
|
||||
split = base.split(':')
|
||||
if len(split) == 2:
|
||||
@@ -214,10 +219,21 @@ class GCCXMLParser(object):
|
||||
base = split[1]
|
||||
else:
|
||||
visib = Scope.public
|
||||
decl = self.GetDecl(base)
|
||||
baseobj = Base(decl.FullName(), visib)
|
||||
baseobjs.append(baseobj)
|
||||
return baseobjs
|
||||
decl = self.GetDecl(base)
|
||||
base = Base(decl.FullName(), visib)
|
||||
this_level.append(base)
|
||||
# normalize with the other levels
|
||||
for index, level in enumerate(decl.hierarchy):
|
||||
if index < len(next_levels):
|
||||
next_levels[index] = next_levels[index] + level
|
||||
else:
|
||||
next_levels.append(level)
|
||||
hierarchy = []
|
||||
if this_level:
|
||||
hierarchy.append(tuple(this_level))
|
||||
if next_levels:
|
||||
hierarchy.extend(next_levels)
|
||||
return hierarchy
|
||||
|
||||
|
||||
def GetMembers(self, members):
|
||||
@@ -237,20 +253,22 @@ class GCCXMLParser(object):
|
||||
context = self.GetDecl(element.get('context'))
|
||||
incomplete = bool(element.get('incomplete', False))
|
||||
if isinstance(context, str):
|
||||
class_ = Class(name, context, [], abstract, [])
|
||||
self.AddDecl(class_)
|
||||
class_ = Class(name, context, [], abstract)
|
||||
else:
|
||||
# a nested class
|
||||
visib = element.get('access', Scope.public)
|
||||
class_ = NestedClass(
|
||||
name, context.FullName(), visib, [], abstract, [])
|
||||
name, context.FullName(), visib, [], abstract)
|
||||
self.AddDecl(class_)
|
||||
# we have to add the declaration of the class before trying
|
||||
# to parse its members and bases, to avoid recursion.
|
||||
class_.location = location
|
||||
class_.incomplete = incomplete
|
||||
self.Update(id, class_)
|
||||
# now we can get the members and the bases
|
||||
class_.bases = self.GetBases(element.get('bases'))
|
||||
class_.hierarchy = self.GetHierarchy(element.get('bases'))
|
||||
if class_.hierarchy:
|
||||
class_.bases = class_.hierarchy[0]
|
||||
class_.members = self.GetMembers(element.get('members'))
|
||||
|
||||
|
||||
@@ -379,11 +397,10 @@ class GCCXMLParser(object):
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, str):
|
||||
enum = Enumeration(name, context)
|
||||
self.AddDecl(enum) # in this case, is a top level decl
|
||||
else:
|
||||
visib = element.get('access', Scope.public)
|
||||
enum = ClassEnumeration(name, context.FullName(), visib)
|
||||
|
||||
self.AddDecl(enum)
|
||||
enum.location = location
|
||||
for child in element:
|
||||
if child.tag == 'EnumValue':
|
||||
|
||||
@@ -8,8 +8,6 @@ Module declarations
|
||||
class Declaration(object):
|
||||
'Represents a basic declaration.'
|
||||
|
||||
__slots__ = 'name namespace location incomplete'.split()
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
# the declaration name
|
||||
self.name = name
|
||||
@@ -44,15 +42,15 @@ class Declaration(object):
|
||||
class Class(Declaration):
|
||||
'The declaration of a class or struct.'
|
||||
|
||||
__slots__= 'members abstract bases _members_count'.split()
|
||||
def __init__(self, name, namespace, members, abstract, bases):
|
||||
def __init__(self, name, namespace, members, abstract):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# list of members
|
||||
self.members = members
|
||||
# whatever the class has any abstract methods
|
||||
self.abstract = abstract
|
||||
# instances of Base
|
||||
self.bases = bases
|
||||
self.bases = ()
|
||||
self.hierarchy = ()
|
||||
self._members_count = {}
|
||||
|
||||
|
||||
@@ -117,10 +115,8 @@ class Class(Declaration):
|
||||
class NestedClass(Class):
|
||||
'The declaration of a class/struct inside another class/struct.'
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
def __init__(self, name, class_, visib, members, abstract, bases):
|
||||
Class.__init__(self, name, None, members, abstract, bases)
|
||||
def __init__(self, name, class_, visib, members, abstract):
|
||||
Class.__init__(self, name, None, members, abstract)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
@@ -133,8 +129,6 @@ class NestedClass(Class):
|
||||
class Base:
|
||||
'Represents a base class of another class.'
|
||||
|
||||
__slots__= 'name visibility'.split()
|
||||
|
||||
def __init__(self, name, visibility=None):
|
||||
# class_ is the full name of the base class
|
||||
self.name = name
|
||||
@@ -155,8 +149,6 @@ class Scope:
|
||||
class Function(Declaration):
|
||||
'The declaration of a function.'
|
||||
|
||||
__slots__= 'result parameters'.split()
|
||||
|
||||
def __init__(self, name, namespace, result, params):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
@@ -206,8 +198,6 @@ class Operator(Function):
|
||||
class Method(Function):
|
||||
'The declaration of a method.'
|
||||
|
||||
__slots__= 'visibility virtual abstract static class_ const'.split()
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
|
||||
Function.__init__(self, name, None, result, params)
|
||||
self.visibility = visib
|
||||
@@ -301,8 +291,6 @@ class ConverterOperator(ClassOperator):
|
||||
class Type(Declaration):
|
||||
'Represents a type.'
|
||||
|
||||
__slots__= 'const default volatile restricted incomplete'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
@@ -339,8 +327,6 @@ class Type(Declaration):
|
||||
class ArrayType(Type):
|
||||
'Represents an array.'
|
||||
|
||||
__slots__= 'min max'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
'min and max can be None.'
|
||||
Type.__init__(self, name, const)
|
||||
@@ -358,8 +344,6 @@ class ArrayType(Type):
|
||||
class ReferenceType(Type):
|
||||
'A reference type.'
|
||||
|
||||
__slots__= 'expand'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandRef=True):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
self.expand = expandRef
|
||||
@@ -383,8 +367,6 @@ class ReferenceType(Type):
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
__slots__= 'expand'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandPointer=False):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
self.expand = expandPointer
|
||||
@@ -415,8 +397,6 @@ class FundamentalType(Type):
|
||||
class FunctionType(Type):
|
||||
'A pointer to a function.'
|
||||
|
||||
__slots__= 'result parameters name'.split()
|
||||
|
||||
def __init__(self, result, parameters):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
@@ -438,8 +418,6 @@ class FunctionType(Type):
|
||||
class MethodType(FunctionType):
|
||||
'A pointer to a member function of a class.'
|
||||
|
||||
__slots__= 'result parameters class_ name'.split()
|
||||
|
||||
def __init__(self, result, parameters, class_):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
@@ -460,8 +438,6 @@ class MethodType(FunctionType):
|
||||
class Variable(Declaration):
|
||||
'Represents a global variable.'
|
||||
|
||||
__slots__= 'type'.split()
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# instance of Type
|
||||
@@ -472,8 +448,6 @@ class Variable(Declaration):
|
||||
class ClassVariable(Variable):
|
||||
'Represents a class variable.'
|
||||
|
||||
__slots__= 'visibility static class_'.split()
|
||||
|
||||
def __init__(self, type, name, class_, visib, static):
|
||||
Variable.__init__(self, type, name, None)
|
||||
self.visibility = visib
|
||||
@@ -488,8 +462,6 @@ class ClassVariable(Variable):
|
||||
|
||||
class Enumeration(Declaration):
|
||||
|
||||
__slots__= 'values'.split()
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.values = {} # dict of str => int
|
||||
@@ -505,8 +477,6 @@ class Enumeration(Declaration):
|
||||
|
||||
class ClassEnumeration(Enumeration):
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Enumeration.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
@@ -525,8 +495,6 @@ class ClassEnumeration(Enumeration):
|
||||
|
||||
class Typedef(Declaration):
|
||||
|
||||
__slots__= 'type visibility'.split()
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.type = type
|
||||
@@ -541,8 +509,6 @@ class Union(Declaration):
|
||||
|
||||
class ClassUnion(Union):
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Union.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
|
||||
@@ -215,3 +215,6 @@ def add_method(info, name, rename=None):
|
||||
info._Attribute('__added__', [(name, rename)])
|
||||
else:
|
||||
added.append((name, rename))
|
||||
|
||||
def no_override(info):
|
||||
info._Attribute('no_override', True)
|
||||
|
||||
@@ -139,6 +139,7 @@ def CreateContext():
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
context['add_method'] = infos.add_method
|
||||
context['no_override'] = infos.no_override
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
|
||||
3
pyste/tests/inherit.cpp
Normal file
3
pyste/tests/inherit.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "inherit.h"
|
||||
|
||||
int inherit::C::s = 1;
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
namespace inherit {
|
||||
|
||||
template<typename T>
|
||||
class A
|
||||
{
|
||||
@@ -16,3 +19,21 @@ class B : public A<int>
|
||||
public:
|
||||
int go() { return get(); }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
{
|
||||
enum ab { a = 1, b = 2 };
|
||||
int f1() { return 1; }
|
||||
int x;
|
||||
static int s;
|
||||
};
|
||||
|
||||
struct D : C
|
||||
{
|
||||
int f2() { return 2; }
|
||||
int y;
|
||||
};
|
||||
|
||||
struct X {};
|
||||
struct E: X, D {};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Doesn't work:
|
||||
A = Template('A', 'inherit.h')
|
||||
A_int = A('int')
|
||||
A = Template('inherit::A', 'inherit.h')
|
||||
A_int = A('int', 'A_int')
|
||||
|
||||
Class('B', 'inherit.h')
|
||||
|
||||
# Does work:
|
||||
#AllFromHeader('inherit.h')
|
||||
Class('inherit::B', 'inherit.h')
|
||||
Class('inherit::D', 'inherit.h')
|
||||
E = Class('inherit::E', 'inherit.h')
|
||||
exclude(E.s)
|
||||
exclude(E.ab)
|
||||
|
||||
@@ -14,6 +14,15 @@ class InheritExampleTest(unittest.TestCase):
|
||||
self.assertEqual(b.go(), 1)
|
||||
self.assertEqual(b.get(), 1)
|
||||
|
||||
d = D()
|
||||
self.assert_(issubclass(D, B))
|
||||
self.assertEqual(d.x, 0)
|
||||
self.assertEqual(d.y, 0)
|
||||
self.assertEqual(d.s, 1)
|
||||
self.assertEqual(D.s, 1)
|
||||
self.assertEqual(d.f1(), 1)
|
||||
self.assertEqual(d.f2(), 2)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
7
pyste/tests/vars.cpp
Normal file
7
pyste/tests/vars.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "vars.h"
|
||||
|
||||
const Color black = Color(0, 0, 0);
|
||||
const Color red = Color(255, 0, 0);
|
||||
const Color green = Color(0, 255, 0);
|
||||
const Color blue = Color(0, 0, 255);
|
||||
Color in_use = black;
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
{
|
||||
return name();
|
||||
}
|
||||
virtual int dummy() { return 0; }
|
||||
|
||||
protected:
|
||||
virtual int f_abs() = 0;
|
||||
@@ -23,6 +24,13 @@ private:
|
||||
virtual const char* name() { return "C"; }
|
||||
};
|
||||
|
||||
struct D
|
||||
{
|
||||
virtual int dummy() { return 0; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c) { return c.f(); }
|
||||
inline int call_dummy(C* c) { return c->dummy(); }
|
||||
inline int call_dummy(D* d) { return d->dummy(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
Class('virtual_::C', 'virtual.h')
|
||||
C = Class('virtual_::C', 'virtual.h')
|
||||
no_override(C.dummy)
|
||||
D = Class('virtual_::D', 'virtual.h')
|
||||
no_override(D.dummy)
|
||||
Function('virtual_::call_f', 'virtual.h')
|
||||
Function('virtual_::call_dummy', 'virtual.h')
|
||||
|
||||
@@ -5,12 +5,14 @@ struct A
|
||||
{
|
||||
virtual int f() { return 0; }
|
||||
virtual int f1() { return 10; }
|
||||
virtual A* make_new() { return new A; }
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
virtual int f() { return 1; }
|
||||
virtual int f2() { return 20; }
|
||||
virtual A* make_new() { return new B; }
|
||||
};
|
||||
|
||||
inline int call_fs(A*a)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Class('virtual2::A', 'virtual2.h')
|
||||
Class('virtual2::B', 'virtual2.h')
|
||||
A = Class('virtual2::A', 'virtual2.h')
|
||||
set_policy(A.make_new, return_value_policy(manage_new_object))
|
||||
B = Class('virtual2::B', 'virtual2.h')
|
||||
set_policy(B.make_new, return_value_policy(manage_new_object))
|
||||
Function('virtual2::call_fs', 'virtual2.h')
|
||||
Function('virtual2::call_f', 'virtual2.h')
|
||||
|
||||
@@ -12,7 +12,14 @@ class Virtual2Test(unittest.TestCase):
|
||||
self.assertEqual(call_fs(b), 30)
|
||||
self.assertEqual(call_f(a), 0)
|
||||
self.assertEqual(call_f(b), 1)
|
||||
|
||||
nb = b.make_new()
|
||||
na = a.make_new()
|
||||
self.assertEqual(na.f1(), 10)
|
||||
self.assertEqual(nb.f1(), 10)
|
||||
self.assertEqual(nb.f2(), 20)
|
||||
self.assertEqual(call_fs(nb), 30)
|
||||
self.assertEqual(call_f(na), 0)
|
||||
self.assertEqual(call_f(nb), 1)
|
||||
class C(B):
|
||||
def f1(self): return 1
|
||||
def f2(self): return 2
|
||||
|
||||
@@ -5,33 +5,45 @@ class VirtualTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
|
||||
class D(C):
|
||||
class E(C):
|
||||
def f_abs(self):
|
||||
return 3
|
||||
def dummy(self):
|
||||
# override should not work
|
||||
return 100
|
||||
|
||||
class E(C):
|
||||
class F(C):
|
||||
def f(self):
|
||||
return 10
|
||||
def name(self):
|
||||
return 'E'
|
||||
return 'F'
|
||||
|
||||
class G(D):
|
||||
def dummy(self):
|
||||
# override should not work
|
||||
return 100
|
||||
|
||||
d = D()
|
||||
e = E()
|
||||
f = F()
|
||||
|
||||
self.assertEqual(d.f(), 3)
|
||||
self.assertEqual(call_f(d), 3)
|
||||
self.assertEqual(e.f(), 10)
|
||||
self.assertEqual(call_f(e), 10)
|
||||
self.assertEqual(d.get_name(), 'C')
|
||||
self.assertEqual(e.f(), 3)
|
||||
self.assertEqual(call_f(e), 3)
|
||||
self.assertEqual(f.f(), 10)
|
||||
self.assertEqual(call_f(f), 10)
|
||||
self.assertEqual(e.get_name(), 'C')
|
||||
#self.assertEqual(e.get_name(), 'E') check this later
|
||||
|
||||
c = C()
|
||||
def bar(arg):
|
||||
c.bar(arg)
|
||||
bar(1) # ok
|
||||
bar('a') # ok
|
||||
self.assertRaises(TypeError, bar, 1.0)
|
||||
|
||||
c.bar(1) # ok
|
||||
c.bar('a') # ok
|
||||
self.assertRaises(TypeError, c.bar, 1.0)
|
||||
|
||||
# test no_overrides
|
||||
d = G()
|
||||
self.assertEqual(e.dummy(), 100)
|
||||
self.assertEqual(call_dummy(e), 0)
|
||||
self.assertEqual(d.dummy(), 100)
|
||||
self.assertEqual(call_dummy(d), 0)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user