2
0
mirror of https://github.com/boostorg/python.git synced 2026-02-01 20:52:13 +00:00

- Fixed "char**" bug

- Lots of internal changes: phase 1 of Meta-Programming complete.


[SVN r18919]
This commit is contained in:
Bruno da Silva de Oliveira
2003-07-03 00:00:23 +00:00
parent 4588f5e9ab
commit d476e67067
23 changed files with 758 additions and 722 deletions

View File

@@ -1,3 +1,7 @@
2 July 2003
Jim Wilson found a bug where types like "char**" were being interpreted as
"char*". Thanks Jim!
16 June 2003
Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours
have changed:

View File

@@ -24,7 +24,8 @@
</tr>
</table>
<p>
Suppose that you want to add a function to a class, turning it into a method:</p>
Suppose that you want to add a function to a class, turning it into a member
function:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>World
</span><span class=special>{
@@ -38,7 +39,7 @@ Suppose that you want to add a function to a class, turning it into a method:</p
}
</span></pre></code>
<p>
Here, we want to make <tt>greet</tt> work as a method of the class <tt>World</tt>. We do
Here, we want to make <tt>greet</tt> work as a member function of the class <tt>World</tt>. We do
that using the <tt>add_method</tt> construct:</p>
<code><pre>
<span class=identifier>W </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
@@ -46,7 +47,7 @@ that using the <tt>add_method</tt> construct:</p>
</span></pre></code>
<p>
Notice also that then you can rename it, set its policy, just like a regular
method:</p>
member function:</p>
<code><pre>
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>W</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=literal>'Greet'</span><span class=special>)
</span></pre></code>

View File

@@ -26,9 +26,9 @@
</table>
<p>
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
<a href="../../doc/tutorial/doc/call_policies.html">
tutorial</a>.</p>
<p>
@@ -44,8 +44,8 @@ becomes in Pyste: </p>
<span class=identifier>return_internal_reference</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>))
</span></pre></code>
<p>
The user can specify policies for functions and methods with the <tt>set_policy</tt>
function:</p>
The user can specify policies for functions and virtual member functions with
the <tt>set_policy</tt> function:</p>
<code><pre>
<span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>f</span><span class=special>, </span><span class=identifier>return_internal_reference</span><span class=special>())
</span><span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>return_value_policy</span><span class=special>(</span><span class=identifier>manage_new_object</span><span class=special>))
@@ -54,10 +54,11 @@ function:</p>
<tr>
<td class="note_box">
<img src="theme/note.gif"></img> <b>What if a function or method needs a policy and the user
doesn't set one?</b><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.
<img src="theme/note.gif"></img> <b>What if a function or member function needs a policy and
the user doesn't set one?</b><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.
</td>
</tr>
</table>
@@ -66,7 +67,7 @@ and set the policy for it, otherwise the generated cpp won't compile.
<td class="note_box">
<img src="theme/note.gif"></img>
Note that, for functions/methods that return <tt>const T&amp;</tt>, the policy
Note that, for functions that return <tt>const T&amp;</tt>, the policy
<tt>return_value_policy&lt;copy_const_reference&gt;()</tt> wil be used by default, because
that's normally what you want. You can change it to something else if you need
to, though.

View File

@@ -25,7 +25,7 @@
</tr>
</table>
<p>
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 <tt>rename</tt>, like this:</p>
<code><pre>
<span class=identifier>World </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
@@ -34,7 +34,7 @@ function <tt>rename</tt>, like this:</p>
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>show</span><span class=special>, </span><span class=string>&quot;Show&quot;</span><span class=special>)
</span></pre></code>
<p>
You can rename methods and attributes using this syntax:</p>
You can rename member functions and attributes using this syntax:</p>
<code><pre>
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>&quot;Greet&quot;</span><span class=special>)
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>&quot;Set&quot;</span><span class=special>)
@@ -43,7 +43,7 @@ You can rename methods and attributes using this syntax:</p>
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>blue</span><span class=special>, </span><span class=string>&quot;Blue&quot;</span><span class=special>)
</span></pre></code>
<p>
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 <tt>exclude</tt>:</p>
<code><pre>
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>)
@@ -59,6 +59,18 @@ To access the operators of a class, access the member <tt>operator</tt> like thi
</span></pre></code>
<p>
The string inside the brackets is the same as the name of the operator in C++.<br></p>
<a name="virtual_member_functions"></a><h2>Virtual Member Functions</h2><p>
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 <tt>final</tt>:</p>
<code><pre>
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
</span><span class=identifier>final</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>) </span>##<span class=identifier>C</span><span class=special>::</span><span class=identifier>foo </span><span class=identifier>is </span><span class=identifier>a </span><span class=keyword>virtual </span><span class=identifier>member </span><span class=identifier>function
</span></pre></code>
<p>
No virtual wrapper code will be generated for the virtual member function
C::foo that way.</p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>

View File

@@ -32,8 +32,8 @@ cpp file with <a href="../../index.html">
Boost.Python</a> code, with all the classes and functions exported.</p>
<p>
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. </p>
options, like renaming e excluding classes and member functionis. Those are
explained later on.</p>
<a name="basics"></a><h2>Basics</h2><p>
Suppose we have a class and some functions that we want to expose to Python
declared in the header <tt>hello.h</tt>:</p>

View File

@@ -75,10 +75,9 @@ You can optionally declare the function in the interface file itself:</p>
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=identifier>names_wrapper</span><span class=special>)
</span></pre></code>
<p>
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
<a href="../../index.html">
Boost.Python</a>:</p>
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:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>C
</span><span class=special>{
@@ -104,7 +103,7 @@ And then in the interface file:</p>
Boost.Python</a> 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 <b>pointer</b>. 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.
</td>
</tr>
</table>

View File

@@ -46,24 +46,24 @@ class ClassExporter(Exporter):
def ScopeName(self):
return makeid(self.class_.FullName()) + '_scope'
return makeid(self.class_._FullName()) + '_scope'
def Unit(self):
return makeid(self.class_.name)
return makeid(self.class_._name)
def Name(self):
return self.class_.FullName()
return self.class_._FullName()
def SetDeclarations(self, declarations):
Exporter.SetDeclarations(self, declarations)
decl = self.GetDeclaration(self.info.name)
if isinstance(decl, Typedef):
self.class_ = self.GetDeclaration(decl.type.name)
self.class_ = self.GetDeclaration(decl._type._name)
if not self.info.rename:
self.info.rename = decl.name
self.info.rename = decl._name
else:
self.class_ = decl
self.class_ = copy.deepcopy(self.class_)
@@ -72,10 +72,10 @@ class ClassExporter(Exporter):
def ClassBases(self):
all_bases = []
for level in self.class_.hierarchy:
for level in self.class_._hierarchy:
for base in level:
all_bases.append(base)
return [self.GetDeclaration(x.name) for x in all_bases]
return [self.GetDeclaration(x._name) for x in all_bases]
def Order(self):
@@ -83,15 +83,13 @@ class ClassExporter(Exporter):
bases' bases. Do this because base classes must be instantialized
before the derived classes in the module definition.
'''
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
return '%s_%s' % (len(self.ClassBases()), self.class_._FullName())
def Export(self, codeunit, exported_names):
self.InheritMethods(exported_names)
self.MakeNonVirtual()
if not self.info.exclude:
self.CheckIsForwardDeclared()
self.CheckForwardDeclarations()
self.ExportBasics()
self.ExportBases(exported_names)
self.ExportConstructors()
@@ -110,43 +108,31 @@ class ClassExporter(Exporter):
'''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
just export one type and automatically get all the members from the
base classes.
'''
valid_members = (Method, ClassVariable, NestedClass, ClassOperator,
ConverterOperator, ClassEnumeration)
for level in self.class_.hierarchy:
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:
base = self.GetDeclaration(base._name)
if base._FullName() not in exported_names:
for member in base:
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)
# member.class_ = self.class_._FullName()
self.class_._AddMember(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 IsValid(member):
return isinstance(member, valid_members) and member._visibility == Scope.public
self.public_members = [x for x in self.class_ if IsValid(x)]
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()
print
def CheckForwardDeclarations(self):
for m in self.public_members:
if isinstance(m, Function):
exporterutils.WarnForwardDeclarations(m)
def Write(self, codeunit):
indent = self.INDENT
boost_ns = namespaces.python
@@ -210,23 +196,22 @@ class ClassExporter(Exporter):
def ExportBasics(self):
'Export the name of the class and its class_ statement'
self.Add('template', self.class_.FullName())
name = self.info.rename or self.class_.name
self.Add('template', self.class_._FullName())
name = self.info.rename or self.class_._name
self.Add('constructor', '"%s"' % name)
def ExportBases(self, exported_names):
'Expose the bases of the class into the template section'
hierarchy = self.class_.hierarchy
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 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):
@@ -238,9 +223,9 @@ class ClassExporter(Exporter):
def init_code(cons):
'return the init<>() code for the given contructor'
param_list = [p.FullName() for p in cons.parameters]
min_params_list = param_list[:cons.minArgs]
max_params_list = param_list[cons.minArgs:]
param_list = [p._FullName() for p in cons._parameters]
min_params_list = param_list[:cons._minArgs]
max_params_list = param_list[cons._minArgs:]
min_params = ', '.join(min_params_list)
max_params = ', '.join(max_params_list)
init = py_ns + 'init< '
@@ -255,9 +240,9 @@ class ClassExporter(Exporter):
constructors = [x for x in self.public_members if isinstance(x, Constructor)]
self.constructors = constructors[:]
# don't export the copy constructor if the class is abstract
if self.class_.abstract:
if self.class_._abstract:
for cons in constructors:
if cons.IsCopy():
if cons._IsCopy():
constructors.remove(cons)
break
if not constructors:
@@ -267,7 +252,7 @@ class ClassExporter(Exporter):
# write the constructor with less parameters to the constructor section
smaller = None
for cons in constructors:
if smaller is None or len(cons.parameters) < len(smaller.parameters):
if smaller is None or len(cons._parameters) < len(smaller._parameters):
smaller = cons
assert smaller is not None
self.Add('constructor', init_code(smaller))
@@ -277,7 +262,7 @@ class ClassExporter(Exporter):
code = '.def(%s)' % init_code(cons)
self.Add('inside', code)
# check if the class is copyable
if not self.class_.HasCopyConstructor() or self.class_.abstract:
if not self.class_._HasCopyConstructor() or self.class_._abstract:
self.Add('template', namespaces.boost + 'noncopyable')
@@ -285,11 +270,11 @@ class ClassExporter(Exporter):
'Export the variables of the class, both static and simple variables'
vars = [x for x in self.public_members if isinstance(x, Variable)]
for var in vars:
if self.info[var.name].exclude:
if self.info[var._name].exclude:
continue
name = self.info[var.name].rename or var.name
fullname = var.FullName()
if var.type.const:
name = self.info[var._name].rename or var._name
fullname = var._FullName()
if var._type._const:
def_ = '.def_readonly'
else:
def_ = '.def_readwrite'
@@ -299,8 +284,8 @@ class ClassExporter(Exporter):
def OverloadName(self, method):
'Returns the name of the overloads struct for the given method'
name = makeid(method.FullName())
overloads = '_overloads_%i_%i' % (method.minArgs, method.maxArgs)
name = makeid(method._FullName())
overloads = '_overloads_%i_%i' % (method._minArgs, method._maxArgs)
return name + overloads
@@ -322,13 +307,13 @@ class ClassExporter(Exporter):
declared = {}
def DeclareOverloads(m):
'Declares the macro for the generation of the overloads'
if (isinstance(m, Method) and m.static) or type(m) == Function:
func = m.FullName()
if (isinstance(m, Method) and m._static) or type(m) == Function:
func = m._FullName()
macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS'
else:
func = m.name
func = m._name
macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS'
code = '%s(%s, %s, %i, %i)\n' % (macro, self.OverloadName(m), func, m.minArgs, m.maxArgs)
code = '%s(%s, %s, %i, %i)\n' % (macro, self.OverloadName(m), func, m._minArgs, m._maxArgs)
if code not in declared:
declared[code] = True
self.Add('declaration', code)
@@ -337,37 +322,29 @@ class ClassExporter(Exporter):
def Pointer(m):
'returns the correct pointer declaration for the method m'
# check if this method has a wrapper set for him
wrapper = self.info[method.name].wrapper
wrapper = self.info[m._name].wrapper
if wrapper:
return '&' + wrapper.FullName()
# return normal pointers to the methods of the class
if isinstance(m, Method):
is_unique = self.class_.IsUnique(m.name)
else:
# function
is_unique = len(self.GetDeclarations(m.FullName())) == 1
if is_unique:
return '&' + method.FullName()
else:
return method.PointerDeclaration()
return m._PointerDeclaration()
def IsExportable(m):
'Returns true if the given method is exportable by this routine'
ignore = (Constructor, ClassOperator, Destructor)
return isinstance(m, Function) and not isinstance(m, ignore) and not m.virtual
return isinstance(m, Function) and not isinstance(m, ignore) and not m._virtual
methods = [x for x in self.public_members if IsExportable(x)]
methods.extend(self.GetAddedMethods())
for method in methods:
method_info = self.info[method.name]
method_info = self.info[method._name]
# skip this method if it was excluded by the user
if method_info.exclude:
continue
# rename the method if the user requested
name = method_info.rename or method.name
name = method_info.rename or method._name
# warn the user if this method needs a policy and doesn't have one
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
@@ -378,7 +355,7 @@ class ClassExporter(Exporter):
policy = ', %s%s()' % (namespaces.python, policy.Code())
# check for overloads
overload = ''
if method.minArgs != method.maxArgs:
if method._minArgs != method._maxArgs:
# add the overloads for this method
DeclareOverloads(method)
overload_name = self.OverloadName(method)
@@ -392,7 +369,7 @@ class ClassExporter(Exporter):
code += ')'
self.Add('inside', code)
# static method
if isinstance(method, Method) and method.static:
if isinstance(method, Method) and method._static:
code = '.staticmethod("%s")' % name
self.Add('inside', code)
# add wrapper code if this method has one
@@ -404,16 +381,16 @@ class ClassExporter(Exporter):
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
for member in self.class_:
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
for member in self.class_.members:
if type(member) == Method and member.virtual:
for member in self.class_:
if type(member) == Method and member._virtual:
has_virtual_methods = True
break
@@ -432,7 +409,7 @@ class ClassExporter(Exporter):
BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS))))
# a dict of operators that are not directly supported by boost, but can be exposed
# simply as a function with a special signature
# simply as a function with a special name
BOOST_RENAME_OPERATORS = {
'()' : '__call__',
}
@@ -459,26 +436,26 @@ class ClassExporter(Exporter):
for decl in self.declarations:
if isinstance(decl, Operator):
# check if one of the params is this class
for param in decl.parameters:
if param.name == self.class_.FullName():
for param in decl._parameters:
if param._name == self.class_._FullName():
operators.append(decl)
break
return operators
def GetOperand(param):
'Returns the operand of this parameter (either "self", or "other<type>")'
if param.name == self.class_.FullName():
if param._name == self.class_._FullName():
return namespaces.python + 'self'
else:
return namespaces.python + ('other< %s >()' % param.name)
return namespaces.python + ('other< %s >()' % param._name)
def HandleSpecialOperator(operator):
# gatter information about the operator and its parameters
result_name = operator.result.name
result_name = operator._result._name
param1_name = ''
if operator.parameters:
param1_name = operator.parameters[0].name
if operator._parameters:
param1_name = operator._parameters[0]._name
# check for str
ostream = 'basic_ostream'
@@ -496,23 +473,21 @@ class ClassExporter(Exporter):
frees = GetFreeOperators()
members = [x for x in self.public_members if type(x) == ClassOperator]
all_operators = frees + members
operators = [x for x in all_operators if not self.info['operator'][x.name].exclude]
operators = [x for x in all_operators if not self.info['operator'][x._name].exclude]
for operator in operators:
# gatter information about the operator, for use later
wrapper = self.info['operator'][operator.name].wrapper
wrapper = self.info['operator'][operator._name].wrapper
if wrapper:
pointer = '&' + wrapper.FullName()
if wrapper.code:
self.Add('declaration', wrapper.code)
elif isinstance(operator, ClassOperator) and self.class_.IsUnique(operator.name):
pointer = '&' + operator.FullName()
else:
pointer = operator.PointerDeclaration()
rename = self.info['operator'][operator.name].rename
pointer = operator._PointerDeclaration()
rename = self.info['operator'][operator._name].rename
# check if this operator will be exported as a method
export_as_method = wrapper or rename or operator.name in self.BOOST_RENAME_OPERATORS
export_as_method = wrapper or rename or operator._name in self.BOOST_RENAME_OPERATORS
# check if this operator has a special representation in boost
special_code = HandleSpecialOperator(operator)
@@ -524,9 +499,9 @@ class ClassExporter(Exporter):
if wrapper:
rename = wrapper.name
else:
rename = self.BOOST_RENAME_OPERATORS[operator.name]
rename = self.BOOST_RENAME_OPERATORS[operator._name]
policy = ''
policy_obj = self.info['operator'][operator.name].policy
policy_obj = self.info['operator'][operator._name].policy
if policy_obj:
policy = ', %s()' % policy_obj.Code()
self.Add('inside', '.def("%s", %s%s)' % (rename, pointer, policy))
@@ -534,24 +509,24 @@ class ClassExporter(Exporter):
elif has_special_representation:
self.Add('inside', special_code)
elif operator.name in self.BOOST_SUPPORTED_OPERATORS:
elif operator._name in self.BOOST_SUPPORTED_OPERATORS:
# export this operator using boost's facilities
op = operator
is_unary = isinstance(op, Operator) and len(op.parameters) == 1 or\
isinstance(op, ClassOperator) and len(op.parameters) == 0
is_unary = isinstance(op, Operator) and len(op._parameters) == 1 or\
isinstance(op, ClassOperator) and len(op._parameters) == 0
if is_unary:
self.Add('inside', '.def( %s%sself )' % \
(operator.name, namespaces.python))
(operator._name, namespaces.python))
else:
# binary operator
if len(operator.parameters) == 2:
left_operand = GetOperand(operator.parameters[0])
right_operand = GetOperand(operator.parameters[1])
if len(operator._parameters) == 2:
left_operand = GetOperand(operator._parameters[0])
right_operand = GetOperand(operator._parameters[1])
else:
left_operand = namespaces.python + 'self'
right_operand = GetOperand(operator.parameters[0])
right_operand = GetOperand(operator._parameters[0])
self.Add('inside', '.def( %s %s %s )' % \
(left_operand, operator.name, right_operand))
(left_operand, operator._name, right_operand))
# export the converters.
# export them as simple functions with a pre-determined name
@@ -559,8 +534,8 @@ class ClassExporter(Exporter):
converters = [x for x in self.public_members if type(x) == ConverterOperator]
def ConverterMethodName(converter):
result_fullname = converter.result.FullName()
result_name = converter.result.name
result_fullname = converter._result._FullName()
result_name = converter._result._name
for regex, method_name in self.SPECIAL_CONVERTERS.items():
if regex.match(result_fullname):
return method_name
@@ -570,7 +545,7 @@ class ClassExporter(Exporter):
return 'to_' + result_name
for converter in converters:
info = self.info['operator'][converter.result.FullName()]
info = self.info['operator'][converter._result._FullName()]
# check if this operator should be excluded
if info.exclude:
continue
@@ -579,10 +554,7 @@ class ClassExporter(Exporter):
if info.rename or not special_code:
# export as method
name = info.rename or ConverterMethodName(converter)
if self.class_.IsUnique(converter.name):
pointer = '&' + converter.FullName()
else:
pointer = converter.PointerDeclaration()
pointer = converter._PointerDeclaration()
policy_code = ''
if info.policy:
policy_code = ', %s()' % info.policy.Code()
@@ -596,9 +568,9 @@ class ClassExporter(Exporter):
def ExportNestedClasses(self, exported_names):
nested_classes = [x for x in self.public_members if isinstance(x, NestedClass)]
for nested_class in nested_classes:
nested_info = self.info[nested_class.name]
nested_info = self.info[nested_class._name]
nested_info.include = self.info.include
nested_info.name = nested_class.FullName()
nested_info.name = nested_class._FullName()
exporter = ClassExporter(nested_info)
exporter.SetDeclarations(self.declarations)
codeunit = SingleCodeUnit(None, None)
@@ -609,9 +581,9 @@ class ClassExporter(Exporter):
def ExportNestedEnums(self):
nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
for enum in nested_enums:
enum_info = self.info[enum.name]
enum_info = self.info[enum._name]
enum_info.include = self.info.include
enum_info.name = enum.FullName()
enum_info.name = enum._FullName()
exporter = EnumExporter(enum_info)
exporter.SetDeclarations(self.declarations)
codeunit = SingleCodeUnit(None, None)
@@ -622,17 +594,9 @@ class ClassExporter(Exporter):
def ExportSmartPointer(self):
smart_ptr = self.info.smart_ptr
if smart_ptr:
class_name = self.class_.FullName()
class_name = self.class_._FullName()
smart_ptr = smart_ptr % class_name
#self.Add('template', smart_ptr)
self.Add('scope', '// Temporary code for smart pointers')
self.Add('scope', namespaces.python + 'objects::class_value_wrapper< ')
self.Add('scope', ' %s, objects::make_ptr_instance< ' % smart_ptr)
self.Add('scope', ' %s, objects::pointer_holder< ' % class_name)
self.Add('scope', ' %s, %s >' % (smart_ptr, class_name))
self.Add('scope', ' >')
self.Add('scope', '>();')
self.Add('scope', '%s::register_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
def ExportOpaquePointerPolicies(self):
@@ -640,8 +604,8 @@ class ClassExporter(Exporter):
methods = [x for x in self.public_members if isinstance(x, Method)]
for method in methods:
return_opaque_policy = return_value_policy(return_opaque_pointer)
if self.info[method.name].policy == return_opaque_policy:
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % method.result.name
if self.info[method._name].policy == return_opaque_policy:
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % method._result._name
if macro not in self._exported_opaque_pointers:
self.Add('declaration-outside', macro)
self._exported_opaque_pointers[macro] = 1
@@ -653,9 +617,9 @@ class ClassExporter(Exporter):
def _ParamsInfo(m, count=None):
if count is None:
count = len(m.parameters)
count = len(m._parameters)
param_names = ['p%i' % i for i in range(count)]
param_types = [x.FullName() for x in m.parameters[:count]]
param_types = [x._FullName() for x in m._parameters[:count]]
params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)]
#for i, p in enumerate(m.parameters[:count]):
# if p.default is not None:
@@ -672,7 +636,7 @@ class _VirtualWrapperGenerator(object):
self.class_ = class_
self.bases = bases[:]
self.info = info
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
self.wrapper_name = makeid(class_._FullName()) + '_Wrapper'
self.virtual_methods = None
self._method_count = {}
self.GenerateVirtualMethods()
@@ -683,9 +647,9 @@ class _VirtualWrapperGenerator(object):
number of default arguments. Always returns at least one name, and return from
the one with most arguments to the one with the least.
'''
base_name = 'default_' + method.name
minArgs = method.minArgs
maxArgs = method.maxArgs
base_name = 'default_' + method._name
minArgs = method._minArgs
maxArgs = method._maxArgs
if minArgs == maxArgs:
return [base_name]
else:
@@ -699,18 +663,18 @@ class _VirtualWrapperGenerator(object):
'''
pyste = namespaces.pyste
python = namespaces.python
rename = self.info[method.name].rename or method.name
result = method.result.FullName()
rename = self.info[method._name].rename or method._name
result = method._result._FullName()
return_str = 'return '
if result == 'void':
return_str = ''
params, param_names, param_types = _ParamsInfo(method)
constantness = ''
if method.const:
if method._const:
constantness = ' const'
# call_method callback
decl = indent + '%s %s(%s)%s {\n' % (result, method.name, params, constantness)
decl = indent + '%s %s(%s)%s {\n' % (result, method._name, params, constantness)
param_names_str = ', '.join(param_names)
if param_names_str:
param_names_str = ', ' + param_names_str
@@ -721,19 +685,19 @@ class _VirtualWrapperGenerator(object):
# default implementations (with overloading)
def DefaultImpl(method, param_names):
'Return the body of a default implementation wrapper'
wrapper = self.info[method.name].wrapper
wrapper = self.info[method._name].wrapper
if not wrapper:
# return the default implementation of the class
return '%s%s::%s(%s);\n' % \
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
(return_str, self.class_._FullName(), method._name, ', '.join(param_names))
else:
# return a call for the wrapper
params = ', '.join(['this'] + param_names)
return '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
if not method.abstract and method.visibility != Scope.private:
minArgs = method.minArgs
maxArgs = method.maxArgs
if not method._abstract and method._visibility != Scope.private:
minArgs = method._minArgs
maxArgs = method._maxArgs
impl_names = self.DefaultImplementationNames(method)
for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)):
params, param_names, param_types = _ParamsInfo(method, argNum)
@@ -749,38 +713,35 @@ class _VirtualWrapperGenerator(object):
statement to export this method.'''
# dont define abstract methods
pyste = namespaces.pyste
rename = self.info[method.name].rename or method.name
rename = self.info[method._name].rename or method._name
default_names = self.DefaultImplementationNames(method)
class_name = self.class_.FullName()
class_name = self.class_._FullName()
wrapper_name = pyste + self.wrapper_name
result = method.result.FullName()
is_method_unique = self.IsMethodUnique(method.name)
result = method._result._FullName()
is_method_unique = method._is_unique
constantness = ''
if method.const:
if method._const:
constantness = ' const'
# create a list of default-impl pointers
minArgs = method.minArgs
maxArgs = method.maxArgs
minArgs = method._minArgs
maxArgs = method._maxArgs
if is_method_unique:
default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names]
else:
default_pointers = []
for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)):
param_list = [x.FullName() for x in method.parameters[:argNum]]
param_list = [x._FullName() for x in method._parameters[:argNum]]
params = ', '.join(param_list)
signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name)
default_pointers.append(default_pointer)
# get the pointer of the method
if is_method_unique:
pointer = '&' + method.FullName()
else:
pointer = method.PointerDeclaration()
pointer = method._PointerDeclaration()
# Add policy to overloaded methods also
policy = self.info[method.name].policy or ''
policy = self.info[method._name].policy or ''
if policy:
policy = ', %s%s()' % (namespaces.python, policy.Code())
@@ -805,14 +766,14 @@ class _VirtualWrapperGenerator(object):
'''
def IsVirtual(m):
return type(m) is Method and \
m.virtual and \
m.visibility != Scope.private
m._virtual and \
m._visibility != Scope.private
all_methods = [x for x in self.class_.members if IsVirtual(x)]
all_methods = [x for x in self.class_ if IsVirtual(x)]
for base in self.bases:
base_methods = [x.Copy() for x in base if IsVirtual(x)]
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
for base_method in base_methods:
base_method.class_ = self.class_.FullName()
base_method.class_ = self.class_._FullName()
all_methods.append(base_method)
# extract the virtual methods, avoiding duplications. The duplication
@@ -820,16 +781,16 @@ class _VirtualWrapperGenerator(object):
# that inherited members are correctly excluded if the subclass overrides
# them.
def MethodSig(method):
if method.const:
if method._const:
const = 'const'
else:
const = ''
if method.result:
result = method.result.FullName()
if method._result:
result = method._result._FullName()
else:
result = ''
params = ', '.join([x.FullName() for x in method.parameters])
return '%s %s(%s) %s' % (result, method.name, params, const)
params = ', '.join([x._FullName() for x in method._parameters])
return '%s %s(%s) %s' % (result, method._name, params, const)
self.virtual_methods = []
already_added = {}
@@ -840,25 +801,16 @@ class _VirtualWrapperGenerator(object):
already_added[sig] = 0
def IsMethodUnique(self, method):
if not self._method_count:
for m in self.virtual_methods:
self._method_count[m.name] = self._method_count.get(m.name, 0) + 1
return self._method_count[method] == 1
def Constructors(self):
def IsValid(m):
return isinstance(m, Constructor) and m.visibility == Scope.public
return [m for m in self.class_.members if IsValid(m)]
return self.class_._Constructors(publics_only=True)
def GenerateDefinitions(self):
defs = []
for method in self.virtual_methods:
exclude = self.info[method.name].exclude
exclude = self.info[method._name].exclude
# generate definitions only for public methods and non-abstract methods
if method.visibility == Scope.public and not method.abstract and not exclude:
if method._visibility == Scope.public and not method._abstract and not exclude:
defs.extend(self.MethodDefinition(method))
return defs
@@ -867,13 +819,13 @@ class _VirtualWrapperGenerator(object):
'Return the wrapper for this class'
# generate the class code
class_name = self.class_.FullName()
class_name = self.class_._FullName()
code = 'struct %s: %s\n' % (self.wrapper_name, class_name)
code += '{\n'
# generate constructors (with the overloads for each one)
for cons in self.Constructors(): # only public constructors
minArgs = cons.minArgs
maxArgs = cons.maxArgs
minArgs = cons._minArgs
maxArgs = cons._maxArgs
# from the min number of arguments to the max number, generate
# all version of the given constructor
cons_code = ''
@@ -889,7 +841,7 @@ class _VirtualWrapperGenerator(object):
# generate the body
body = []
for method in self.virtual_methods:
if not self.info[method.name].exclude:
if not self.info[method._name].exclude:
body.append(self.Declaration(method, indent))
body = '\n'.join(body)
code += body + '\n'

View File

@@ -21,16 +21,16 @@ class EnumExporter(Exporter):
if not self.info.exclude:
indent = self.INDENT
in_indent = self.INDENT*2
rename = self.info.rename or self.enum.name
full_name = self.enum.FullName()
rename = self.info.rename or self.enum._name
full_name = self.enum._FullName()
if rename == "$_0" or rename == '._0':
full_name = "int"
rename = "unnamed"
code = indent + namespaces.python
code += 'enum_< %s >("%s")\n' % (full_name, rename)
for name in self.enum.values:
for name in self.enum._values:
rename = self.info[name].rename or name
value_fullname = self.enum.ValueFullName(name)
value_fullname = self.enum._ValueFullName(name)
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
code += indent + ';\n\n'
codeunit.Write('module', code)

View File

@@ -55,7 +55,7 @@ class Exporter:
def GetDeclarations(self, fullname):
decls = []
for decl in self.declarations:
if decl.FullName() == fullname:
if decl._FullName() == fullname:
decls.append(decl)
if not decls:
raise RuntimeError, 'no %s declaration found!' % fullname

View File

@@ -22,22 +22,19 @@ class FunctionExporter(Exporter):
decls = self.GetDeclarations(self.info.name)
for decl in decls:
self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
exporterutils.WarnForwardDeclarations(decl)
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
self.ExportOpaquePointer(decl, codeunit)
self.GenerateOverloads(decls, codeunit)
def ExportDeclaration(self, decl, unique, codeunit):
name = self.info.rename or decl.name
name = self.info.rename or decl._name
defs = namespaces.python + 'def("%s", ' % name
wrapper = self.info.wrapper
if wrapper:
pointer = '&' + wrapper.FullName()
elif not unique:
pointer = decl.PointerDeclaration()
else:
pointer = '&' + decl.FullName()
pointer = decl._PointerDeclaration()
defs += pointer
defs += self.PolicyCode()
overload = self.OverloadName(decl)
@@ -51,9 +48,9 @@ class FunctionExporter(Exporter):
def OverloadName(self, decl):
if decl.minArgs != decl.maxArgs:
if decl._minArgs != decl._maxArgs:
return '%s_overloads_%i_%i' % \
(decl.name, decl.minArgs, decl.maxArgs)
(decl._name, decl._minArgs, decl._maxArgs)
else:
return ''
@@ -64,7 +61,7 @@ class FunctionExporter(Exporter):
overload = self.OverloadName(decl)
if overload and overload not in codes:
code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\
(overload, decl.FullName(), decl.minArgs, decl.maxArgs)
(overload, decl._FullName(), decl._minArgs, decl_.maxArgs)
codeunit.Write('declaration', code + '\n')
codes[overload] = None
@@ -80,7 +77,7 @@ class FunctionExporter(Exporter):
def ExportOpaquePointer(self, function, codeunit):
if self.info.policy == return_value_policy(return_opaque_pointer):
type = function.result.name
type = function._result._name
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % type
if macro not in self._exported_opaque_pointers:
codeunit.Write('declaration-outside', macro)

View File

@@ -5,6 +5,9 @@ from copy import deepcopy
from utils import enumerate
#==============================================================================
# Exceptions
#==============================================================================
class InvalidXMLError(Exception): pass
class ParserError(Exception): pass
@@ -12,6 +15,9 @@ class ParserError(Exception): pass
class InvalidContextError(ParserError): pass
#==============================================================================
# GCCXMLParser
#==============================================================================
class GCCXMLParser(object):
'Parse a GCC_XML file and extract the top-level declarations.'
@@ -21,6 +27,7 @@ class GCCXMLParser(object):
self.elements = self.GetElementsFromXML(filename)
# high level declarations
self.declarations = []
self._names = {}
# parse the elements
for id in self.elements:
element, decl = self.elements[id]
@@ -37,6 +44,12 @@ class GCCXMLParser(object):
def AddDecl(self, decl):
if decl._FullName() in self._names:
decl._is_unique= False
for d in self.declarations:
if d._FullName() == decl._FullName():
d._is_unique = False
self._names[decl._FullName()] = 0
self.declarations.append(decl)
@@ -102,18 +115,17 @@ class GCCXMLParser(object):
restricted, id = Check(id, 'r')
decl = self.GetDecl(id)
if isinstance(decl, Type):
res = decl.Copy()
res = deepcopy(decl)
if const:
res.const = const
res._const = const
if volatile:
res.volatile = volatile
res._volatile = volatile
if restricted:
res.restricted = restricted
res._restricted = restricted
else:
res = Type(decl.FullName(), const)
res.volatile = volatile
res.restricted = restricted
res.incomplete = decl.incomplete
res = Type(decl._FullName(), const)
res._volatile = volatile
res._restricted = restricted
return res
@@ -130,8 +142,7 @@ class GCCXMLParser(object):
def ParseUnknown(self, id, element):
name = '__Unknown_Element_%s' % id
namespace = '::'
decl = Declaration(name, namespace)
decl = Unknown(name)
self.Update(id, decl)
@@ -139,10 +150,10 @@ class GCCXMLParser(object):
namespace = element.get('name')
context = element.get('context')
if context:
outerns = self.GetDecl(context)
if not outerns.endswith('::'):
outerns += '::'
namespace = outerns + namespace
outer = self.GetDecl(context)
if not outer.endswith('::'):
outer += '::'
namespace = outer + namespace
if namespace.startswith('::'):
namespace = namespace[2:]
self.Update(id, namespace)
@@ -155,19 +166,19 @@ class GCCXMLParser(object):
def ParseVariable(self, id, element):
# in gcc_xml, a static Field is declared as a Variable, so we check
# this and call the Field parser if apply.
# this and call the Field parser.
context = self.GetDecl(element.get('context'))
if isinstance(context, Class):
self.ParseField(id, element)
elem, decl = self.elements[id]
decl.static = True
decl._static = True
else:
namespace = context
name = element.get('name')
type_ = self.GetType(element.get('type'))
location = self.GetLocation(element.get('location'))
variable = Variable(type_, name, namespace)
variable.location = location
variable._location = location
self.AddDecl(variable)
self.Update(id, variable)
@@ -176,9 +187,9 @@ class GCCXMLParser(object):
args = []
for child in element:
if child.tag == 'Argument':
type_ = self.GetType(child.get('type'))
type_.default = child.get('default')
args.append(type_)
type = self.GetType(child.get('type'))
type._default = child.get('default')
args.append(type)
return args
@@ -190,8 +201,9 @@ class GCCXMLParser(object):
namespace = self.GetDecl(element.get('context'))
location = self.GetLocation(element.get('location'))
params = self.GetArguments(element)
incomplete = bool(int(element.get('incomplete', 0)))
function = functionType(name, namespace, returns, params)
function.location = location
function._location = location
self.AddDecl(function)
self.Update(id, function)
@@ -225,10 +237,10 @@ class GCCXMLParser(object):
# "Unimplemented" tag, but we are not interested in this classes
# anyway
continue
base = Base(decl.FullName(), visib)
base = Base(decl._FullName(), visib)
this_level.append(base)
# normalize with the other levels
for index, level in enumerate(decl.hierarchy):
for index, level in enumerate(decl._hierarchy):
if index < len(next_levels):
next_levels[index] = next_levels[index] + level
else:
@@ -256,25 +268,27 @@ class GCCXMLParser(object):
abstract = bool(int(element.get('abstract', '0')))
location = self.GetLocation(element.get('location'))
context = self.GetDecl(element.get('context'))
incomplete = bool(element.get('incomplete', False))
incomplete = bool(int(element.get('incomplete', 0)))
if isinstance(context, str):
class_ = Class(name, context, [], abstract)
else:
# a nested class
visib = element.get('access', Scope.public)
class_ = NestedClass(
name, context.FullName(), visib, [], abstract)
self.AddDecl(class_)
name, context._FullName(), visib, [], abstract)
class_._incomplete = incomplete
# 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.AddDecl(class_)
class_._location = location
self.Update(id, class_)
# now we can get the members and the bases
class_.hierarchy = self.GetHierarchy(element.get('bases'))
if class_.hierarchy:
class_.bases = class_.hierarchy[0]
class_.members = self.GetMembers(element.get('members'))
class_._hierarchy = self.GetHierarchy(element.get('bases'))
if class_._hierarchy:
class_._bases = class_._hierarchy[0]
members = self.GetMembers(element.get('members'))
for member in members:
class_._AddMember(member)
def ParseStruct(self, id, element):
@@ -288,26 +302,24 @@ class GCCXMLParser(object):
def ParseArrayType(self, id, element):
type_ = self.GetType(element.get('type'))
type = self.GetType(element.get('type'))
min = element.get('min')
max = element.get('max')
array = ArrayType(type_.name, type_.const)
array.min = min
array.max = max
array = ArrayType(type._name, type._const, min, max)
self.Update(id, array)
def ParseReferenceType(self, id, element):
type_ = self.GetType(element.get('type'))
expand = not isinstance(type_, FunctionType)
ref = ReferenceType(type_.name, type_.const, None, type_.incomplete, expand)
type = self.GetType(element.get('type'))
expand = not isinstance(type, FunctionType)
ref = ReferenceType(type._name, type._const, None, expand, type._suffix)
self.Update(id, ref)
def ParsePointerType(self, id, element):
type_ = self.GetType(element.get('type'))
expand = not isinstance(type_, FunctionType)
ref = PointerType(type_.name, type_.const, None, type_.incomplete, expand)
type = self.GetType(element.get('type'))
expand = not isinstance(type, FunctionType)
ref = PointerType(type._name, type._const, None, expand, type._suffix)
self.Update(id, ref)
@@ -319,7 +331,7 @@ class GCCXMLParser(object):
def ParseMethodType(self, id, element):
class_ = self.GetDecl(element.get('basetype')).FullName()
class_ = self.GetDecl(element.get('basetype'))._FullName()
result = self.GetType(element.get('returns'))
args = self.GetArguments(element)
method = MethodType(result, args, class_)
@@ -329,19 +341,19 @@ class GCCXMLParser(object):
def ParseField(self, id, element):
name = element.get('name')
visib = element.get('access', Scope.public)
classname = self.GetDecl(element.get('context')).FullName()
classname = self.GetDecl(element.get('context'))._FullName()
type_ = self.GetType(element.get('type'))
static = bool(int(element.get('extern', '0')))
location = self.GetLocation(element.get('location'))
var = ClassVariable(type_, name, classname, visib, static)
var.location = location
var._location = location
self.Update(id, var)
def ParseMethod(self, id, element, methodType=Method):
name = element.get('name')
result = self.GetType(element.get('returns'))
classname = self.GetDecl(element.get('context')).FullName()
classname = self.GetDecl(element.get('context'))._FullName()
visib = element.get('access', Scope.public)
static = bool(int(element.get('static', '0')))
virtual = bool(int(element.get('virtual', '0')))
@@ -351,7 +363,7 @@ class GCCXMLParser(object):
params = self.GetArguments(element)
method = methodType(
name, classname, result, params, visib, virtual, abstract, static, const)
method.location = location
method._location = location
self.Update(id, method)
@@ -362,22 +374,22 @@ class GCCXMLParser(object):
def ParseConstructor(self, id, element):
name = element.get('name')
visib = element.get('access', Scope.public)
classname = self.GetDecl(element.get('context')).FullName()
classname = self.GetDecl(element.get('context'))._FullName()
location = self.GetLocation(element.get('location'))
params = self.GetArguments(element)
ctor = Constructor(name, classname, params, visib)
ctor.location = location
ctor._location = location
self.Update(id, ctor)
def ParseDestructor(self, id, element):
name = element.get('name')
visib = element.get('access', Scope.public)
classname = self.GetDecl(element.get('context')).FullName()
classname = self.GetDecl(element.get('context'))._FullName()
virtual = bool(int(element.get('virtual', '0')))
location = self.GetLocation(element.get('location'))
des = Destructor(name, classname, visib, virtual)
des.location = location
des._location = location
self.Update(id, des)
@@ -390,7 +402,7 @@ class GCCXMLParser(object):
type = self.GetType(element.get('type'))
context = self.GetDecl(element.get('context'))
if isinstance(context, Class):
context = context.FullName()
context = context._FullName()
typedef = Typedef(type, name, context)
self.Update(id, typedef)
self.AddDecl(typedef)
@@ -400,41 +412,23 @@ class GCCXMLParser(object):
name = element.get('name')
location = self.GetLocation(element.get('location'))
context = self.GetDecl(element.get('context'))
incomplete = bool(int(element.get('incomplete', 0)))
if isinstance(context, str):
enum = Enumeration(name, context)
else:
visib = element.get('access', Scope.public)
enum = ClassEnumeration(name, context.FullName(), visib)
enum = ClassEnumeration(name, context._FullName(), visib)
self.AddDecl(enum)
enum.location = location
enum._location = location
for child in element:
if child.tag == 'EnumValue':
name = child.get('name')
value = int(child.get('init'))
enum.values[name] = value
enum._values[name] = value
enum._incomplete = incomplete
self.Update(id, enum)
def ParseUnimplemented(self, id, element):
'No idea of what this is'
self.Update(id, Declaration('', ''))
def ParseUnion(self, id, element):
name = element.get('name')
context = self.GetDecl(element.get('context'))
location = self.GetLocation(element.get('location'))
if isinstance(context, str):
# a free union
union = Union(name, context)
self.AddDecl(union)
else:
visib = element.get('access', Scope.public)
union = ClassUnion(name, context.FullName(), visib)
union.location = location
self.Update(id, union)
def ParseDeclarations(filename):
'Returns a list of the top declarations found in the gcc_xml file.'

View File

@@ -32,8 +32,8 @@ class HeaderExporter(Exporter):
header = os.path.normpath(self.parser_header)
for decl in self.declarations:
# check if this declaration is in the header
location = os.path.normpath(decl.location[0])
if location == header and not self.IsInternalName(decl.name):
location = os.path.normpath(decl._location[0])
if location == header and not self.IsInternalName(decl._name):
# ok, check the type of the declaration and export it accordingly
self.HandleDeclaration(decl, codeunit, exported_names)
@@ -57,9 +57,9 @@ class HeaderExporter(Exporter):
def HandleExporter(self, decl, exporter_type, codeunit, exported_names):
# only export complete declarations
if not getattr(decl, "incomplete", False):
info = self.info[decl.name]
info.name = decl.FullName()
if not getattr(decl, "_incomplete", False):
info = self.info[decl._name]
info.name = decl._FullName()
info.include = self.info.include
exporter = exporter_type(info)
exporter.SetDeclarations(self.declarations)
@@ -69,7 +69,7 @@ class HeaderExporter(Exporter):
def Unit(self):
return None # doesn't write anything by himself
return None # doesn't write anything by itself
def Order(self):

View File

@@ -16,7 +16,7 @@ class VarExporter(Exporter):
def Export(self, codeunit, exported_names):
if self.info.exclude: return
decl = self.GetDeclaration(self.info.name)
if not decl.type.const:
if not decl._type._const:
msg = '---> Warning: The global variable "%s" is non-const:\n' \
' changes in Python will not reflect in C++.'
print msg % self.info.name

View File

@@ -1,305 +1,386 @@
'''
Module declarations
Defines classes that represent declarations found in C++ header files.
Defines classes that represent declarations found in C++ header files.
'''
#==============================================================================
# Declaration
#==============================================================================
class Declaration(object):
'Represents a basic declaration.'
'''Base class for all declarations.
@ivar _name: The name of the declaration.
@ivar _namespace: The namespace of the declaration.
'''
def __init__(self, name, namespace):
# the declaration name
self.name = name
# all the namespaces, separated by '::' = 'boost::inner'
self.namespace = namespace
# tuple (filename, line)
self.location = '', -1
# if a declaration is incomplete it means that it was
# forward declared
self.incomplete = False
'''
@type name: string
@param name: The name of this declaration
@type namespace: string
@param namespace: the full namespace where this declaration resides.
'''
self._name = name
self._namespace = namespace
self._location = '', -1 # (filename, line)
self._incomplete = False
self._is_unique = True
def FullName(self):
'Returns the full qualified name: "boost::inner::Test"'
namespace = self.namespace or ''
#if not namespace:
# namespace = ''
def _FullName(self):
'''
Returns the full qualified name: "boost::inner::Test"
@rtype: string
@return: The full name of the declaration.
'''
namespace = self._namespace or ''
if namespace and not namespace.endswith('::'):
namespace += '::'
return namespace + self.name
return namespace + self._name
def __repr__(self):
return '<Declaration %s at %s>' % (self.FullName(), id(self))
return '<Declaration %s at %s>' % (self._FullName(), id(self))
def __str__(self):
return 'Declaration of %s' % self.FullName()
return 'Declaration of %s' % self._FullName()
#==============================================================================
# Class
#==============================================================================
class Class(Declaration):
'The declaration of a class or struct.'
'''
Represents a C++ class or struct. Iteration through it yields its members.
@type _abstract: bool
@ivar _abstract: if the class has any abstract methods.
@type _bases: tuple
@ivar _bases: tuple with L{Base} instances, representing the most direct
inheritance.
@type _hierarchy: list
@ivar _hierarchy: a list of tuples of L{Base} instances, representing
the entire hierarchy tree of this object. The first tuple is the parent
classes, and the other ones go up in the hierarchy.
'''
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 = ()
self.hierarchy = ()
self._members_count = {}
self.__members = members
self._abstract = abstract
self._bases = ()
self._hierarchy = ()
self.operator = {}
def __iter__(self):
return iter(self.members)
'''iterates through the class' members.
'''
return iter(self.__members)
def IsAbstract(self):
'Returns True if any method of this class is abstract'
for member in self.members:
if isinstance(member, Method):
if member.abstract:
return True
return False
def RawName(self):
'Returns the raw name of a template class. name = Foo<int>, raw = Foo'
lesspos = self.name.find('<')
if lesspos != -1:
return self.name[:lesspos]
else:
return self.name
def Constructors(self, publics_only=True):
def _Constructors(self, publics_only=True):
'''Returns a list of the constructors for this class.
@rtype: list
'''
constructors = []
for member in self:
if isinstance(member, Constructor):
if publics_only and member.visibility != Scope.public:
if publics_only and member._visibility != Scope.public:
continue
constructors.append(member)
return constructors
def HasCopyConstructor(self):
for cons in self.Constructors():
if cons.IsCopy():
def _HasCopyConstructor(self):
'''Returns true if this class has a public copy constructor.
@rtype: bool
'''
for cons in self._Constructors():
if cons._IsCopy():
return True
return False
def HasDefaultConstructor(self):
def _HasDefaultConstructor(self):
'''Returns true if this class has a public default constructor.
@rtype: bool
'''
for cons in self.Constructors():
if cons.IsDefault():
if cons._IsDefault():
return True
return False
def IsUnique(self, member_name):
if not self._members_count:
for m in self:
self._members_count[m.name] = self._members_count.get(m.name, 0) + 1
try:
return self._members_count[member_name] == 1
except KeyError:
print self._members_count
print 'Key', member_name
def _AddMember(self, member):
slot = getattr(self, member._name, [])
if slot:
member._is_unique = False
for m in slot:
m._is_unique = False
slot.append(member)
setattr(self, member._name, slot)
self.__members.append(member)
if isinstance(member, ClassOperator):
self.operator[member._name] = member
#==============================================================================
# NestedClass
#==============================================================================
class NestedClass(Class):
'The declaration of a class/struct inside another class/struct.'
'''The declaration of a class/struct inside another class/struct.
@type _class: string
@ivar _class: fullname of the class where this class is contained.
def __init__(self, name, class_, visib, members, abstract):
@type _visibility: L{Scope}
@ivar _visibility: the visibility of this class.
'''
def __init__(self, name, _class, visib, members, abstract):
Class.__init__(self, name, None, members, abstract)
self.class_ = class_
self.visibility = visib
self._class = _class
self._visibility = visib
def FullName(self):
return '%s::%s' % (self.class_, self.name)
def _FullName(self):
'''The full name of this class, like ns::outer::inner.
@rtype: string
'''
return '%s::%s' % (self._class, self._name)
class Base:
'Represents a base class of another class.'
def __init__(self, name, visibility=None):
# class_ is the full name of the base class
self.name = name
# visibility of the derivation
if visibility is None:
visibility = Scope.public
self.visibility = visibility
class Scope:
#==============================================================================
# Scope
#==============================================================================
class Scope:
'''Used to represent the visibility of various members inside a class.
@cvar public: public visibility
@cvar private: private visibility
@cvar protected: protected visibility
'''
public = 'public'
private = 'private'
protected = 'protected'
#==============================================================================
# Base
#==============================================================================
class Base:
'''Represents a base class of another class.
@ivar _name: the full name of the base class.
@ivar _visibility: the visibility of the derivation.
'''
def __init__(self, name, visibility=Scope.public):
self._name = name
self._visibility = visibility
#==============================================================================
# Function
#==============================================================================
class Function(Declaration):
'The declaration of a function.'
'''The declaration of a function.
@ivar _result: instance of L{Type} or None.
@ivar _parameters: list of L{Type} instances.
'''
def __init__(self, name, namespace, result, params):
Declaration.__init__(self, name, namespace)
# the result type: instance of Type, or None (constructors)
self.result = result
self._result = result
# the parameters: instances of Type
self.parameters = params
self._parameters = params
def PointerDeclaration(self):
'returns a declaration of a pointer to this function'
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
return '(%s (*)(%s))&%s' % (result, params, self.FullName())
def _PointerDeclaration(self, force=False):
'''Returns a declaration of a pointer to this function.
@param force: If True, returns a complete pointer declaration regardless
if this function is unique or not.
'''
if self._is_unique and not force:
return '&%s' % self._FullName()
else:
result = self._result._FullName()
params = ', '.join([x._FullName() for x in self._parameters])
return '(%s (*)(%s))&%s' % (result, params, self._FullName())
def _MinArgs(self):
min = 0
for arg in self.parameters:
if arg.default is None:
for arg in self._parameters:
if arg._default is None:
min += 1
return min
minArgs = property(_MinArgs)
_minArgs = property(_MinArgs)
def _MaxArgs(self):
return len(self.parameters)
return len(self._parameters)
maxArgs = property(_MaxArgs)
_maxArgs = property(_MaxArgs)
def Copy(self):
return self.__class__(
self.name, self.namespace, self.result, self.params[:])
#==============================================================================
# Operator
#==============================================================================
class Operator(Function):
'The declaration of a custom operator.'
'''The declaration of a custom operator. Its name is the same as the
operator name in C++, ie, the name of the declaration "operator+(..)" is
"+".
'''
def FullName(self):
namespace = self.namespace or ''
def _FullName(self):
namespace = self._namespace or ''
if not namespace.endswith('::'):
namespace += '::'
return namespace + 'operator' + self.name
return namespace + 'operator' + self._name
#==============================================================================
# Method
#==============================================================================
class Method(Function):
'The declaration of a method.'
'''The declaration of a method.
@ivar _visibility: the visibility of this method.
@ivar _virtual: if this method is declared as virtual.
@ivar _abstract: if this method is virtual but has no default implementation.
@ivar _static: if this method is static.
@ivar _class: the full name of the class where this method was declared.
@ivar _const: if this method is declared as const.
'''
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
Function.__init__(self, name, None, result, params)
self.visibility = visib
self.virtual = virtual
self.abstract = abstract
self.static = static
self.class_ = class_
self.const = const
self._visibility = visib
self._virtual = virtual
self._abstract = abstract
self._static = static
self._class = class_
self._const = const
def FullName(self):
return self.class_ + '::' + self.name
def _FullName(self):
return self._class + '::' + self._name
def PointerDeclaration(self):
'returns a declaration of a pointer to this function'
if self.static:
def _PointerDeclaration(self, force=False):
'''Returns a declaration of a pointer to this member function.
@param force: If True, returns a complete pointer declaration regardless
if this function is unique or not.
'''
if self._static:
# static methods are like normal functions
return Function.PointerDeclaration(self)
return Function._PointerDeclaration(self, force)
if self._is_unique and not force:
return '&%s' % self._FullName()
else:
# using syntax of methods
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
result = self._result._FullName()
params = ', '.join([x._FullName() for x in self._parameters])
const = ''
if self.const:
if self._const:
const = 'const'
return '(%s (%s::*)(%s) %s)&%s' %\
(result, self.class_, params, const, self.FullName())
(result, self._class, params, const, self._FullName())
def Copy(self):
return self.__class__(
self.name,
self.class_,
self.result,
self.parameters[:],
self.visibility,
self.virtual,
self.abstract,
self.static,
self.const)
#==============================================================================
# Constructor
#==============================================================================
class Constructor(Method):
'A constructor of a class.'
'''A class' constructor.
'''
def __init__(self, name, class_, params, visib):
Method.__init__(self, name, class_, None, params, visib, False, False, False, False)
def IsDefault(self):
return len(self.parameters) == 0
def _IsDefault(self):
'''Returns True if this constructor is a default constructor.
'''
return len(self._parameters) == 0 and self._visibility == Scope.public
def IsCopy(self):
if len(self.parameters) != 1:
def _IsCopy(self):
'''Returns True if this constructor is a copy constructor.
'''
if len(self._parameters) != 1:
return False
param = self.parameters[0]
class_as_param = self.parameters[0].name == self.class_
param = self._parameters[0]
class_as_param = self._parameters[0]._name == self._class
param_reference = isinstance(param, ReferenceType)
return param_reference and class_as_param and param.const
is_public = self._visibility = Scope.public
return param_reference and class_as_param and param._const and is_public
#==============================================================================
# Destructor
#==============================================================================
class Destructor(Method):
'The destructor of a class.'
def __init__(self, name, class_, visib, virtual):
Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False)
def FullName(self):
return self.class_ + '::~' + self.name
def _FullName(self):
return self._class + '::~' + self._name
#==============================================================================
# ClassOperator
#==============================================================================
class ClassOperator(Method):
'The declaration of a custom operator in a class.'
'A custom operator in a class.'
def FullName(self):
return self.class_ + '::operator ' + self.name
def _FullName(self):
return self._class + '::operator ' + self._name
#==============================================================================
# ConverterOperator
#==============================================================================
class ConverterOperator(ClassOperator):
'An operator in the form "operator OtherClass()".'
def FullName(self):
return self.class_ + '::operator ' + self.result.FullName()
def _FullName(self):
return self._class + '::operator ' + self._result._FullName()
#==============================================================================
# Type
#==============================================================================
class Type(Declaration):
'Represents a type.'
'''Represents the type of a variable or parameter.
@ivar _const: if the type is constant.
@ivar _default: if this type has a default value associated with it.
@ivar _volatile: if this type was declared with the keyword volatile.
@ivar _restricted: if this type was declared with the keyword restricted.
@ivar _suffix: Suffix to get the full type name. '*' for pointers, for
example.
'''
def __init__(self, name, const=False, default=None, incomplete=False):
def __init__(self, name, const=False, default=None, suffix=''):
Declaration.__init__(self, name, None)
# whatever the type is constant or not
self.const = const
self._const = const
# used when the Type is a function argument
self.default = default
self.volatile = False
self.restricted = False
self.incomplete = incomplete
self._default = default
self._volatile = False
self._restricted = False
self._suffix = suffix
def __repr__(self):
if self.const:
@@ -309,166 +390,171 @@ class Type(Declaration):
return '<Type ' + const + self.name + '>'
def FullName(self):
if self.const:
def _FullName(self):
if self._const:
const = 'const '
else:
const = ''
return const + self.name
def Copy(self):
t = self.__class__(self.name, self.const, self.default, self.incomplete)
t.volatile = self.volatile
t.restricted = self.restricted
return t
return const + self._name + self._suffix
#==============================================================================
# ArrayType
#==============================================================================
class ArrayType(Type):
'Represents an array.'
'''Represents an array.
@ivar min: the lower bound of the array, usually 0. Can be None.
@ivar max: the upper bound of the array. Can be None.
'''
def __init__(self, name, const=False, default=None, incomplete=False):
def __init__(self, name, const, min, max):
'min and max can be None.'
Type.__init__(self, name, const)
self.min = None
self.max = None
def Copy(self):
t = Type.Copy(self)
t.min = self.min
t.max = self.max
return t
self.min = min
self.max = max
#==============================================================================
# ReferenceType
#==============================================================================
class ReferenceType(Type):
'A reference type.'
'''A reference type.'''
def __init__(self, name, const=False, default=None, incomplete=False, expandRef=True):
Type.__init__(self, name, const, default, incomplete)
self.expand = expandRef
def __init__(self, name, const=False, default=None, expandRef=True, suffix=''):
Type.__init__(self, name, const, default)
if expandRef:
self._suffix = suffix + '&'
def FullName(self):
'expand is False for function pointers'
expand = ' &'
if not self.expand:
expand = ''
return Type.FullName(self) + expand
def Copy(self):
t = Type.Copy(self)
t.expand = self.expand
return t
#==============================================================================
# PointerType
#==============================================================================
class PointerType(Type):
'A pointer type.'
def __init__(self, name, const=False, default=None, incomplete=False, expandPointer=False):
Type.__init__(self, name, const, default, incomplete)
self.expand = expandPointer
def FullName(self):
'expand is False for function pointer'
expand = ' *'
if not self.expand:
expand = ''
return Type.FullName(self) + expand
def Copy(self):
t = Type.Copy(self)
t.expand = self.expand
return t
def __init__(self, name, const=False, default=None, expandPointer=False, suffix=''):
Type.__init__(self, name, const, default)
if expandPointer:
self._suffix = suffix + '*'
#==============================================================================
# FundamentalType
#==============================================================================
class FundamentalType(Type):
'One of the fundamental types (int, void...).'
'One of the fundamental types, like int, void, etc.'
def __init__(self, name, const=False, default=None, incomplete=False):
Type.__init__(self, name, const, default, incomplete)
def __init__(self, name, const=False, default=None):
Type.__init__(self, name, const, default)
#==============================================================================
# FunctionType
#==============================================================================
class FunctionType(Type):
'A pointer to a function.'
'''A pointer to a function.
@ivar _result: the return value
@ivar _parameters: a list of Types, indicating the parameters of the function.
@ivar _name: the name of the function.
'''
def __init__(self, result, parameters):
Type.__init__(self, '', False)
self.result = result
self.parameters = parameters
self.name = self.FullName()
self._result = result
self._parameters = parameters
self._name = self._FullName()
def FullName(self):
full = '%s (*)' % self.result.FullName()
params = [x.FullName() for x in self.parameters]
def _FullName(self):
full = '%s (*)' % self._result._FullName()
params = [x._FullName() for x in self._parameters]
full += '(%s)' % ', '.join(params)
return full
def Copy(self):
return FunctionType(self.result, self.parameters[:])
#==============================================================================
# MethodType
#==============================================================================
class MethodType(FunctionType):
'A pointer to a member function of a class.'
'''A pointer to a member function of a class.
@ivar _class: The fullname of the class that the method belongs to.
'''
def __init__(self, result, parameters, class_):
Type.__init__(self, '', False)
self.result = result
self.parameters = parameters
self.class_ = class_
self.name = self.FullName()
self._class = class_
FunctionType.__init__(self, result, parameters)
def FullName(self):
full = '%s (%s::*)' % (self.result.FullName(), self.class_)
params = [x.FullName() for x in self.parameters]
def _FullName(self):
full = '%s (%s::*)' % (self._result._FullName(), self._class)
params = [x._FullName() for x in self._parameters]
full += '(%s)' % ', '.join(params)
return full
def Copy(self):
return MethodType(self.result, self.parameters[:], self.class_)
#==============================================================================
# Variable
#==============================================================================
class Variable(Declaration):
'Represents a global variable.'
'''Represents a global variable.
@type _type: L{Type}
@ivar _type: The type of the variable.
'''
def __init__(self, type, name, namespace):
Declaration.__init__(self, name, namespace)
# instance of Type
self.type = type
self._type = type
#==============================================================================
# ClassVariable
#==============================================================================
class ClassVariable(Variable):
'Represents a class variable.'
'''Represents a class variable.
@type _visibility: L{Scope}
@ivar _visibility: The visibility of this variable within the class.
@type _static: bool
@ivar _static: Indicates if the variable is static.
@ivar _class: Full name of the class that this variable belongs to.
'''
def __init__(self, type, name, class_, visib, static):
Variable.__init__(self, type, name, None)
self.visibility = visib
self.static = static
self.class_ = class_
self._visibility = visib
self._static = static
self._class = class_
def FullName(self):
return self.class_ + '::' + self.name
def _FullName(self):
return self._class + '::' + self._name
#==============================================================================
# Enumeration
#==============================================================================
class Enumeration(Declaration):
'''Represents an enum.
@type _values: dict of str => int
@ivar _values: holds the values for this enum.
'''
def __init__(self, name, namespace):
Declaration.__init__(self, name, namespace)
self.values = {} # dict of str => int
self._values = {} # dict of str => int
def ValueFullName(self, name):
assert name in self.values
namespace = self.namespace
def _ValueFullName(self, name):
'''Returns the full name for a value in the enum.
'''
assert name in self._values
namespace = self._namespace
if namespace:
namespace += '::'
return namespace + name
@@ -476,45 +562,52 @@ class Enumeration(Declaration):
class ClassEnumeration(Enumeration):
'''Represents an enum inside a class.
@ivar _class: The full name of the class where this enum belongs.
@ivar _visibility: The visibility of this enum inside his class.
'''
def __init__(self, name, class_, visib):
Enumeration.__init__(self, name, None)
self.class_ = class_
self.visibility = visib
self._class = class_
self._visibility = visib
def FullName(self):
return '%s::%s' % (self.class_, self.name)
def _FullName(self):
return '%s::%s' % (self._class, self._name)
def ValueFullName(self, name):
assert name in self.values
return '%s::%s' % (self.class_, name)
def _ValueFullName(self, name):
assert name in self._values
return '%s::%s' % (self._class, name)
#==============================================================================
# Typedef
#==============================================================================
class Typedef(Declaration):
'''A Typedef declaration.
@type _type: L{Type}
@ivar _type: The type of the typedef.
@type _visibility: L{Scope}
@ivar _visibility: The visibility of this typedef.
'''
def __init__(self, type, name, namespace):
Declaration.__init__(self, name, namespace)
self.type = type
self.visibility = Scope.public
self._type = type
self._visibility = Scope.public
class Union(Declaration):
'Shallow declaration, because Unions are not supported yet'
def __init__(self, name, namespace):
Declaration.__init__(self, name, namespace)
class ClassUnion(Union):
def __init__(self, name, class_, visib):
Union.__init__(self, name, None)
self.class_ = class_
self.visibility = visib
def FullName(self):
return '%s::%s' % (self.class_, self.name)
#==============================================================================
# Unknown
#==============================================================================
class Unknown(Declaration):
'''A declaration that Pyste does not know how to handle.
'''
def __init__(self, name):
Declaration.__init__(self, name, None)

View File

@@ -41,17 +41,17 @@ def HandlePolicy(function, policy):
def IsString(type):
'Return True if the Type instance can be considered a string'
return type.const and type.name == 'char' and isinstance(type, PointerType)
return type._FullName() == 'const char*'
def IsPyObject(type):
return type.FullName() == '_object *' # internal name of PyObject
return type._FullName() == '_object *' # internal name of PyObject
result = function.result
result = function._result
# if the function returns const char*, a policy is not needed
if IsString(result) or IsPyObject(result):
return policy
# if returns a const T&, set the default policy
if policy is None and result.const and isinstance(result, ReferenceType):
if policy is None and result._const and isinstance(result, ReferenceType):
policy = return_value_policy(copy_const_reference)
# basic test if the result type demands a policy
needs_policy = isinstance(result, (ReferenceType, PointerType))
@@ -59,7 +59,7 @@ def HandlePolicy(function, policy):
if needs_policy and policy is None:
global _printed_warnings
warning = '---> Error: %s returns a pointer or a reference, ' \
'but no policy was specified.' % function.FullName()
'but no policy was specified.' % function._FullName()
if warning not in _printed_warnings:
print warning
print
@@ -69,23 +69,4 @@ def HandlePolicy(function, policy):
#==============================================================================
# WarnForwardDeclarations
#==============================================================================
def WarnForwardDeclarations(function):
'''Checks if any of the parameters or the result of the function are
incomplete types.'''
types = [function.result] + function.parameters
types = [x for x in types if x]
for type in types:
if type.incomplete:
msg = '---> Error: %s is forward declared. Please include the ' \
'appropriate header with its definition' % type.name
# disable this for now... it was reporting too many false
# forward declarations to be useful
if 0 and msg not in _printed_warnings:
print msg
print
_printed_warnings[msg] = 1

View File

@@ -39,7 +39,7 @@ from policies import *
from CppParser import CppParser, CppParserError
import time
__VERSION__ = '0.9.5'
__VERSION__ = '0.9.6'
def RecursiveIncludes(include):
'Return a list containg the include dir and all its subdirectories'

View File

@@ -1,5 +1,6 @@
from __future__ import generators
import string
import sys
#==============================================================================
# enumerate
@@ -45,3 +46,24 @@ def remove_duplicated_lines(text):
def left_equals(s):
s = '// %s ' % s
return s + ('='*(80-len(s))) + '\n'
#==============================================================================
# post_mortem
#==============================================================================
def post_mortem():
def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
pdb.pm()
sys.excepthook = info

View File

@@ -1,5 +1,5 @@
import sys
sys.path.append('..')
sys.path.append('../src')
import unittest
import tempfile
import os.path
@@ -11,36 +11,36 @@ class Tester(unittest.TestCase):
def TestConstructor(self, class_, method, visib):
self.assert_(isinstance(method, Constructor))
self.assertEqual(method.FullName(), class_.FullName() + '::' + method.name)
self.assertEqual(method.result, None)
self.assertEqual(method.visibility, visib)
self.assert_(not method.virtual)
self.assert_(not method.abstract)
self.assert_(not method.static)
self.assertEqual(method._FullName(), class_._FullName() + '::' + method._name)
self.assertEqual(method._result, None)
self.assertEqual(method._visibility, visib)
self.assert_(not method._virtual)
self.assert_(not method._abstract)
self.assert_(not method._static)
def TestDefaultConstructor(self, class_, method, visib):
self.TestConstructor(class_, method, visib)
self.assert_(method.IsDefault())
self.assert_(method._IsDefault())
def TestCopyConstructor(self, class_, method, visib):
self.TestConstructor(class_, method, visib)
self.assertEqual(len(method.parameters), 1)
param = method.parameters[0]
self.assertEqual(len(method._parameters), 1)
param = method._parameters[0]
self.TestType(
param,
ReferenceType,
class_.FullName(),
'const %s &' % class_.FullName(),
class_._FullName(),
'const %s&' % class_._FullName(),
True)
self.assert_(method.IsCopy())
self.assert_(method._IsCopy())
def TestType(self, type_, classtype_, name, fullname, const):
self.assert_(isinstance(type_, classtype_))
self.assertEqual(type_.name, name)
self.assertEqual(type_.namespace, None)
self.assertEqual(type_.FullName(), fullname)
self.assertEqual(type_.const, const)
self.assertEqual(type_._name, name)
self.assertEqual(type_._namespace, None)
self.assertEqual(type_._FullName(), fullname)
self.assertEqual(type_._const, const)
class ClassBaseTest(Tester):
@@ -51,49 +51,48 @@ class ClassBaseTest(Tester):
def testClass(self):
'test the properties of the class Base'
self.assert_(isinstance(self.base, Class))
self.assert_(self.base.abstract)
self.assertEqual(self.base.RawName(), 'Base')
self.assert_(self.base._abstract)
def testFoo(self):
'test function foo in class Base'
foo = GetMember(self.base, 'foo')
self.assert_(isinstance(foo, Method))
self.assertEqual(foo.visibility, Scope.public)
self.assert_(foo.virtual)
self.assert_(foo.abstract)
self.failIf(foo.static)
self.assertEqual(foo.class_, 'test::Base')
self.failIf(foo.const)
self.assertEqual(foo.FullName(), 'test::Base::foo')
self.assertEqual(foo.result.name, 'void')
self.assertEqual(len(foo.parameters), 1)
param = foo.parameters[0]
self.assertEqual(foo._visibility, Scope.public)
self.assert_(foo._virtual)
self.assert_(foo._abstract)
self.failIf(foo._static)
self.assertEqual(foo._class, 'test::Base')
self.failIf(foo._const)
self.assertEqual(foo._FullName(), 'test::Base::foo')
self.assertEqual(foo._result._name, 'void')
self.assertEqual(len(foo._parameters), 1)
param = foo._parameters[0]
self.TestType(param, FundamentalType, 'int', 'int', False)
self.assertEqual(foo.namespace, None)
self.assertEqual(foo._namespace, None)
self.assertEqual(
foo.PointerDeclaration(), '(void (test::Base::*)(int) )&test::Base::foo')
foo._PointerDeclaration(1), '(void (test::Base::*)(int) )&test::Base::foo')
def testX(self):
'test the member x in class Base'
x = GetMember(self.base, 'x')
self.assertEqual(x.class_, 'test::Base')
self.assertEqual(x.FullName(), 'test::Base::x')
self.assertEqual(x.namespace, None)
self.assertEqual(x.visibility, Scope.private)
self.TestType(x.type, FundamentalType, 'int', 'int', False)
self.assertEqual(x.static, False)
self.assertEqual(x._class, 'test::Base')
self.assertEqual(x._FullName(), 'test::Base::x')
self.assertEqual(x._namespace, None)
self.assertEqual(x._visibility, Scope.private)
self.TestType(x._type, FundamentalType, 'int', 'int', False)
self.assertEqual(x._static, False)
def testConstructors(self):
'test constructors in class Base'
constructors = GetMembers(self.base, 'Base')
for cons in constructors:
if len(cons.parameters) == 0:
if len(cons._parameters) == 0:
self.TestDefaultConstructor(self.base, cons, Scope.public)
elif len(cons.parameters) == 1: # copy constructor
elif len(cons._parameters) == 1: # copy constructor
self.TestCopyConstructor(self.base, cons, Scope.public)
elif len(cons.parameters) == 2: # other constructor
intp, floatp = cons.parameters
elif len(cons._parameters) == 2: # other constructor
intp, floatp = cons._parameters
self.TestType(intp, FundamentalType, 'int', 'int', False)
self.TestType(floatp, FundamentalType, 'float', 'float', False)
@@ -101,25 +100,25 @@ class ClassBaseTest(Tester):
'test function simple in class Base'
simple = GetMember(self.base, 'simple')
self.assert_(isinstance(simple, Method))
self.assertEqual(simple.visibility, Scope.protected)
self.assertEqual(simple.FullName(), 'test::Base::simple')
self.assertEqual(len(simple.parameters), 1)
param = simple.parameters[0]
self.TestType(param, ReferenceType, 'std::string', 'const std::string &', True)
self.TestType(simple.result, FundamentalType, 'bool', 'bool', False)
self.assertEqual(simple._visibility, Scope.protected)
self.assertEqual(simple._FullName(), 'test::Base::simple')
self.assertEqual(len(simple._parameters), 1)
param = simple._parameters[0]
self.TestType(param, ReferenceType, 'std::string', 'const std::string&', True)
self.TestType(simple._result, FundamentalType, 'bool', 'bool', False)
self.assertEqual(
simple.PointerDeclaration(),
'(bool (test::Base::*)(const std::string &) )&test::Base::simple')
simple._PointerDeclaration(1),
'(bool (test::Base::*)(const std::string&) )&test::Base::simple')
def testZ(self):
z = GetMember(self.base, 'z')
self.assert_(isinstance(z, Variable))
self.assertEqual(z.visibility, Scope.public)
self.assertEqual(z.FullName(), 'test::Base::z')
self.assertEqual(z.type.name, 'int')
self.assertEqual(z.type.const, False)
self.assert_(z.static)
self.assertEqual(z._visibility, Scope.public)
self.assertEqual(z._FullName(), 'test::Base::z')
self.assertEqual(z._type._name, 'int')
self.assertEqual(z._type._const, False)
self.assert_(z._static)
class ClassTemplateTest(Tester):
@@ -130,19 +129,18 @@ class ClassTemplateTest(Tester):
def testClass(self):
'test the properties of the Template<int> class'
self.assert_(isinstance(self.template, Class))
self.assert_(not self.template.abstract)
self.assertEqual(self.template.FullName(), 'Template<int>')
self.assertEqual(self.template.namespace, '')
self.assertEqual(self.template.name, 'Template<int>')
self.assertEqual(self.template.RawName(), 'Template')
self.assert_(not self.template._abstract)
self.assertEqual(self.template._FullName(), 'Template<int>')
self.assertEqual(self.template._namespace, '')
self.assertEqual(self.template._name, 'Template<int>')
def testConstructors(self):
'test the automatic constructors of the class Template<int>'
constructors = GetMembers(self.template, 'Template')
for cons in constructors:
if len(cons.parameters) == 0:
if len(cons._parameters) == 0:
self.TestDefaultConstructor(self.template, cons, Scope.public)
elif len(cons.parameters) == 1:
elif len(cons._parameters) == 1:
self.TestCopyConstructor(self.template, cons, Scope.public)
@@ -150,21 +148,21 @@ class ClassTemplateTest(Tester):
'test the class variable value'
value = GetMember(self.template, 'value')
self.assert_(isinstance(value, ClassVariable))
self.assert_(value.name, 'value')
self.TestType(value.type, FundamentalType, 'int', 'int', False)
self.assert_(not value.static)
self.assertEqual(value.visibility, Scope.public)
self.assertEqual(value.class_, 'Template<int>')
self.assertEqual(value.FullName(), 'Template<int>::value')
self.assert_(value._name, 'value')
self.TestType(value._type, FundamentalType, 'int', 'int', False)
self.assert_(not value._static)
self.assertEqual(value._visibility, Scope.public)
self.assertEqual(value._class, 'Template<int>')
self.assertEqual(value._FullName(), 'Template<int>::value')
def testBase(self):
'test the superclasses of Template<int>'
bases = self.template.bases
bases = self.template._bases
self.assertEqual(len(bases), 1)
base = bases[0]
self.assert_(isinstance(base, Base))
self.assertEqual(base.name, 'test::Base')
self.assertEqual(base.visibility, Scope.protected)
self.assertEqual(base._name, 'test::Base')
self.assertEqual(base._visibility, Scope.protected)
@@ -176,27 +174,27 @@ class FreeFuncTest(Tester):
def testFunc(self):
'test attributes of FreeFunc'
self.assert_(isinstance(self.func, Function))
self.assertEqual(self.func.name, 'FreeFunc')
self.assertEqual(self.func.FullName(), 'test::FreeFunc')
self.assertEqual(self.func.namespace, 'test')
self.assertEqual(self.func._name, 'FreeFunc')
self.assertEqual(self.func._FullName(), 'test::FreeFunc')
self.assertEqual(self.func._namespace, 'test')
self.assertEqual(
self.func.PointerDeclaration(),
'(const test::Base & (*)(const std::string &, int))&test::FreeFunc')
self.func._PointerDeclaration(1),
'(const test::Base& (*)(const std::string&, int))&test::FreeFunc')
def testResult(self):
'test the return value of FreeFunc'
res = self.func.result
self.TestType(res, ReferenceType, 'test::Base', 'const test::Base &', True)
res = self.func._result
self.TestType(res, ReferenceType, 'test::Base', 'const test::Base&', True)
def testParameters(self):
'test the parameters of FreeFunc'
self.assertEqual(len(self.func.parameters), 2)
strp, intp = self.func.parameters
self.TestType(strp, ReferenceType, 'std::string', 'const std::string &', True)
self.assertEqual(strp.default, None)
self.assertEqual(len(self.func._parameters), 2)
strp, intp = self.func._parameters
self.TestType(strp, ReferenceType, 'std::string', 'const std::string&', True)
self.assertEqual(strp._default, None)
self.TestType(intp, FundamentalType, 'int', 'int', False)
self.assertEqual(intp.default, '10')
self.assertEqual(intp._default, '10')
@@ -205,14 +203,14 @@ class testFunctionPointers(Tester):
def testMethodPointer(self):
'test declaration of a pointer-to-method'
meth = GetDecl('MethodTester')
param = meth.parameters[0]
param = meth._parameters[0]
fullname = 'void (test::Base::*)(int)'
self.TestType(param, PointerType, fullname, fullname, False)
def testFunctionPointer(self):
'test declaration of a pointer-to-function'
func = GetDecl('FunctionTester')
param = func.parameters[0]
param = func._parameters[0]
fullname = 'void (*)(int)'
self.TestType(param, PointerType, fullname, fullname, False)
@@ -297,7 +295,7 @@ declarations = GetDeclarations()
def GetDecl(name):
'returns one of the top declarations given its name'
for decl in declarations:
if decl.name == name:
if decl._name == name:
return decl
else:
raise RuntimeError, 'Declaration not found: %s' % name
@@ -309,7 +307,7 @@ def GetMember(class_, name):
res = None
multipleFound = False
for member in class_:
if member.name == name:
if member._name == name:
if res is not None:
multipleFound = True
break
@@ -317,7 +315,7 @@ def GetMember(class_, name):
if res is None or multipleFound:
raise RuntimeError, \
'No member or more than one member found in class %s: %s' \
% (class_.name, name)
% (class_._name, name)
return res
@@ -325,12 +323,12 @@ def GetMembers(class_, name):
'gets the members of the given class by its name'
res = []
for member in class_:
if member.name == name:
if member._name == name:
res.append(member)
if len(res) in (0, 1):
raise RuntimeError, \
'GetMembers: 0 or 1 members found in class %s: %s' \
% (class_.name, name)
% (class_._name, name)
return res

View File

@@ -19,10 +19,12 @@ struct C
return x+1;
}
const std::string& name() { return _name; }
void set_name(const std::string& name) { _name = name; }
std::string _name;
const std::string& get_name() { return name; }
void set_name(const std::string& name) { this->name = name; }
private:
std::string name;
public:
// test data members
static int static_value;
static const int const_static_value;

View File

@@ -2,8 +2,6 @@
#define OPERATORS_H
#include <iostream>
namespace operators {
struct C

View File

@@ -118,7 +118,7 @@ if __name__ == '__main__':
else:
module = None
try:
main('--multiple', module)
#main('--multiple', module)
main('', module)
except RuntimeError, e:
print e

View File

@@ -1,16 +0,0 @@
namespace unions {
class UnionTest
{
public:
union // unions are not supported for now
{
int i;
short s1;
short s2;
} mBad;
int mGood;
};
}

View File

@@ -1,2 +0,0 @@
UnionTest = Class('unions::UnionTest', 'unions.h')
exclude(UnionTest.mBad)