Remove a bunch of obsolete files.
28
class.cpp
@@ -1,28 +0,0 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/python/module.hpp>
|
||||
#include <boost/python/def.hpp>
|
||||
#include <boost/python/object.hpp>
|
||||
#include <boost/python/class.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
struct X
|
||||
{
|
||||
int x;
|
||||
X(int n) : x(n) { }
|
||||
};
|
||||
|
||||
int x_function(X& x)
|
||||
{ return x.x;
|
||||
}
|
||||
|
||||
|
||||
BOOST_PYTHON_MODULE(class_ext)
|
||||
{
|
||||
class_<X>("X", init<int>());
|
||||
def("x_function", x_function);
|
||||
}
|
||||
|
||||
#include "module_tail.cpp"
|
||||
12
index.html
@@ -1,12 +0,0 @@
|
||||
<!-- Copyright David Abrahams 2006. Distributed under the Boost -->
|
||||
<!-- Software License, Version 1.0. (See accompanying -->
|
||||
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatically loading index page... if nothing happens, please go to
|
||||
<a href="doc/index.html">doc/index.html</a>.
|
||||
</body>
|
||||
</html>
|
||||
212
pyste/NEWS
@@ -1,212 +0,0 @@
|
||||
.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
.. Software License, Version 1.0. (See accompanying
|
||||
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
25 April 2005
|
||||
- Fixed bug where the code for wrappers of member functions were defined outside
|
||||
the pyste namespace. Reported by Dan Haffey.
|
||||
|
||||
9 October 2004
|
||||
- Applied a patch by Christian Hudon that fixed an issue with files
|
||||
that had a tail and relative includes.
|
||||
|
||||
18 July 2004
|
||||
- Applied a patch by Paul Bridger that solves some problems for wrapper
|
||||
methods.
|
||||
- Applied a patch by Baptiste Lepilleur that allows the user to inject
|
||||
code inside the class definition.
|
||||
- Applied another patch by Baptiste Lepilleur that inserts two new command-line
|
||||
options that helps with writing makefiles.
|
||||
|
||||
27 May 2004
|
||||
Applied patch by Paul Bridger that solves a problem on windows regarding
|
||||
spaces on paths. Thanks Paul!
|
||||
|
||||
Applied another patch that fixes the module name if pyste is run from
|
||||
another directory of where the .pyste file is located. Patch contributted
|
||||
by Paul Bridger.
|
||||
|
||||
17 May 2004
|
||||
Applied a patch by Roman Yakovenko that makes the export of unnamed enums
|
||||
better. Thanks Roman!
|
||||
|
||||
23 October 2003
|
||||
Fixed bug where a class would appear more than one in the generated code.
|
||||
|
||||
6 October 2003
|
||||
Fixed bug reported by Niall Douglas (using his patch) about UniqueInt not
|
||||
appearing correctly with --multiple.
|
||||
|
||||
Added precompiled header support on windows systems (using #pragma hdrstop).
|
||||
Suggested by Niall Douglas.
|
||||
|
||||
Fixed a bug with -I directive and AllFromHeader. Reported by Scott Snyder.
|
||||
|
||||
4 October 2003
|
||||
Added return_self, thanks for Niall Douglas for pointing out that it was
|
||||
missing.
|
||||
|
||||
Added --file-list, where you can pass a file where the pyste files are listed
|
||||
one per line. Also suggested by Niall Douglas.
|
||||
|
||||
Documentation has been finally updated, after a long wait. Please let me know
|
||||
if you spot any mistake!
|
||||
|
||||
2 October 2003
|
||||
Scott Snyder found a typo in ClassExporter that prevented -= and *= operators
|
||||
from being exported. Thanks Scott!
|
||||
|
||||
20 September 2003
|
||||
Added return_by_value in the list of policies supported. Thanks to Niall
|
||||
Douglas for the remainder.
|
||||
|
||||
19 September 2003
|
||||
Better support for unnamed enums, plus they are by default exported to the
|
||||
parent's namespace. Normal enums can have the same behaviour using the function
|
||||
export_values on the Enum object. Feature requested by Niall Douglas.
|
||||
|
||||
10 September 2003
|
||||
A new variable is accessible in the Pyste files: INTERFACE_FILE contains the
|
||||
full path of the pyste file.
|
||||
|
||||
4 September 2003
|
||||
Now it is possible to override protected and private pure virtual functions
|
||||
in Python, as requested by Roman Yakovenko.
|
||||
|
||||
23 August 2003
|
||||
Fixed bug where some Imports where not writing their include files.
|
||||
Now whenever the declarations change, the cache files are rebuilt
|
||||
automatically.
|
||||
|
||||
19 August 2003
|
||||
Fixed a bug related to the generation of the bases<> template.
|
||||
|
||||
17 August 2003
|
||||
Added support for insertion of user code in the generated code.
|
||||
|
||||
16 August 2003
|
||||
Applied a patch by Gottfried Ganssauge that adds exception specifiers to
|
||||
wrapper functions and pointer declarations. Thanks a lot Gottfried!!
|
||||
|
||||
Applied a patch by Prabhu Ramachandran that fixes ae problem with the
|
||||
pure virtual method generation. Thanks again Prabhu!
|
||||
|
||||
10 August 2003
|
||||
Support for incremental generation of the code has been added. This changes
|
||||
how --multiple works; documentation of this new feature will follow. Thanks
|
||||
to Prabhu Ramachandran, that saw the need for this feature and discussed a
|
||||
solution.
|
||||
|
||||
Automatically convert \ to / in Windows systems before passing the paths to
|
||||
gccxml.
|
||||
|
||||
Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual
|
||||
methods were being definied incorrectly. Thanks a lot Prabhu!
|
||||
|
||||
7 July 2003
|
||||
Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method,
|
||||
and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr.
|
||||
Thanks a lot Prabhu!
|
||||
|
||||
Fixed a bug where the macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID was being
|
||||
called multiple times for the same type.
|
||||
Thanks to Gottfried Ganßauge for reporting this!
|
||||
|
||||
Fixed bug where using AllFromHeader didn't use bases<> when exporting
|
||||
hierarchies.
|
||||
|
||||
Fixed the staticmethod bug.
|
||||
|
||||
5 July 2003
|
||||
Changed how --multiple works: now it generates one cpp file for each pyste
|
||||
file, makeing easier to integrate Pyste with build systems.
|
||||
|
||||
4 July 2003
|
||||
Applied patch that solved a bug in ClassExporter and added a distutils install
|
||||
script (install/setup.py), both contributed by Prabhu Ramachandran.
|
||||
Thanks Prabhu!
|
||||
|
||||
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:
|
||||
|
||||
- If you export a derived class without exporting its base classes, the derived
|
||||
class will explicitly export the bases's methods and attributes. Before, if
|
||||
you were interested in the bases's methods, you had to export the base
|
||||
classes too.
|
||||
|
||||
- Added a new function, no_override. When a member function is specified as
|
||||
"no_override", no virtual wrappers are generated for it, improving
|
||||
performance and letting the code more clean.
|
||||
|
||||
- There was a bug in which the policy of virtual member functions was being
|
||||
ignored (patch by Roman Sulzhyk).
|
||||
|
||||
Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig.
|
||||
|
||||
4 June 2003
|
||||
Major improvements in memory usage.
|
||||
|
||||
3 June 2003
|
||||
Appliced a patch from Giulio Eulisse that allows unnamed enumerations to be
|
||||
exported with an AllFromHeader construct. Thanks a lot Giulio!
|
||||
|
||||
2 June 2003
|
||||
Added a new construct, add_method. See documentation.
|
||||
|
||||
23 May 2003
|
||||
Support for global variables added.
|
||||
Various bug fixes.
|
||||
|
||||
08 May 2003
|
||||
Fixed bug where in a certain cases the GCCXMLParser would end up with multiple
|
||||
declarations of the same class
|
||||
|
||||
22 Apr 2003
|
||||
- Now shows a warning when the user tries to export a forward-declared class.
|
||||
Forward-declared classes are ignored by the AllFromHeader construct.
|
||||
- Fixed a bug where classes, functions and enums where being exported, even if
|
||||
excluded from a AllFromHeader construct.
|
||||
|
||||
16 Apr 2003
|
||||
Added a more generic (but ugly) code to declare the smart pointer converters.
|
||||
|
||||
07 Apr 2003
|
||||
- Removed the warnings about forward declarations: it was not accurate enough.
|
||||
Another strategy must be thought of.
|
||||
- Fixed bug in the --multiple mode, where the order of the class instantiations
|
||||
could end up wrong.
|
||||
- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk!
|
||||
- Fixed support for the return_opaque_pointer policy (the support macro was not
|
||||
being declared).
|
||||
|
||||
|
||||
06 Apr 2003
|
||||
Support for the improved static data members support of Boost.Python.
|
||||
|
||||
05 Apr 2003
|
||||
New option for generating the bindings: --multiple.
|
||||
|
||||
02 Apr 2003
|
||||
Forward declarations are now detected and a warning is generated.
|
||||
|
||||
24 Mar 2003
|
||||
Default policy for functions/methods that return const T& is now
|
||||
return_value_policy<copy_const_reference>().
|
||||
|
||||
22 Mar 2003
|
||||
Exporting virtual methods of the base classes in the derived classes too.
|
||||
|
||||
21 Mar 2003
|
||||
Added manual support for boost::shared_ptr and std::auto_ptr (see doc).
|
||||
|
||||
19 Mar 2003
|
||||
Added support for int, double, float and long operators acting as expected in
|
||||
python.
|
||||
|
||||
14 Mar 2003
|
||||
Fixed bug: Wrappers for protected and virtual methods were not being generated.
|
||||
35
pyste/README
@@ -1,35 +0,0 @@
|
||||
.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
.. Software License, Version 1.0. (See accompanying
|
||||
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Pyste - Python Semi-Automatic Exporter
|
||||
======================================
|
||||
|
||||
Pyste is a Boost.Python code generator. The user specifies the classes and
|
||||
functions to be exported using a simple interface file, which following the
|
||||
Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to
|
||||
parse all the headers and extract the necessary information to automatically
|
||||
generate C++ code.
|
||||
|
||||
The documentation can be found in the file index.html accompaning this README.
|
||||
|
||||
Enjoy!
|
||||
Bruno da Silva de Oliveira (nicodemus@esss.com.br)
|
||||
|
||||
Thanks
|
||||
======
|
||||
|
||||
- David Abrahams, creator of Boost.Python, for tips on the syntax of the interface
|
||||
file and support.
|
||||
- Marcelo Camelo, for design tips, support and inspiration for this project.
|
||||
Also, the name was his idea. 8)
|
||||
- Brad King, creator of the excellent GCCXML (http://www.gccxml.org)
|
||||
- Fredrik Lundh, creator of the elementtree library (http://effbot.org)
|
||||
|
||||
Bugs
|
||||
====
|
||||
|
||||
Pyste is a young tool, so please help it to get better! Send bug reports to
|
||||
nicodemus@esss.com.br, accompaining the stack trace in case of exceptions.
|
||||
If possible, run pyste with --debug, and send the resulting xmls too (pyste
|
||||
will output a xml file with the same of each header it parsed).
|
||||
18
pyste/TODO
@@ -1,18 +0,0 @@
|
||||
.. Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
.. Software License, Version 1.0. (See accompanying
|
||||
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
- Make Pyste accept already-generated xml files
|
||||
|
||||
- throw() declaration in virtual wrapper's member functions
|
||||
|
||||
- Allow protected methods to be overriden in Python
|
||||
|
||||
- Expose programmability to the Pyste files (listing members of a class, for
|
||||
instance)
|
||||
|
||||
- Virtual operators
|
||||
|
||||
- args() support
|
||||
|
||||
- set policies to methods with the same name
|
||||
55
pyste/dist/create_build.py
vendored
@@ -1,55 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
# Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import fnmatch
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
|
||||
def findfiles(directory, mask):
|
||||
def visit(files, dir, names):
|
||||
for name in names:
|
||||
if fnmatch.fnmatch(name, mask):
|
||||
files.append(os.path.join(dir, name))
|
||||
files = []
|
||||
os.path.walk(directory, visit, files)
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
# test if PyXML is installed
|
||||
try:
|
||||
import _xmlplus.parsers.expat
|
||||
pyxml = '--includes _xmlplus.parsers.expat'
|
||||
except ImportError:
|
||||
pyxml = ''
|
||||
# create exe
|
||||
status = os.system('python setup.py py2exe %s >& build.log' % pyxml)
|
||||
if status != 0:
|
||||
raise RuntimeError, 'Error creating EXE'
|
||||
|
||||
# create distribution
|
||||
import pyste
|
||||
version = pyste.__VERSION__
|
||||
zip = ZipFile('pyste-%s.zip' % version, 'w', ZIP_DEFLATED)
|
||||
# include the base files
|
||||
dist_dir = 'dist/pyste'
|
||||
for basefile in os.listdir(dist_dir):
|
||||
zip.write(os.path.join(dist_dir, basefile), os.path.join('pyste', basefile))
|
||||
# include documentation
|
||||
for doc_file in findfiles('../doc', '*.*'):
|
||||
dest_name = os.path.join('pyste/doc', doc_file[3:])
|
||||
zip.write(doc_file, dest_name)
|
||||
zip.write('../index.html', 'pyste/doc/index.html')
|
||||
zip.close()
|
||||
# cleanup
|
||||
os.remove('build.log')
|
||||
shutil.rmtree('build')
|
||||
shutil.rmtree('dist')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.path.append('../src')
|
||||
main()
|
||||
10
pyste/dist/setup.py
vendored
@@ -1,10 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
# Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
|
||||
sys.path.append('../src')
|
||||
setup(name='pyste', scripts=['../src/pyste.py'])
|
||||
@@ -1,79 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Adding New Methods</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="global_variables.html">
|
||||
<link rel="next" href="inserting_code.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Adding New Methods</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="global_variables.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="inserting_code.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<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>{
|
||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>(</span><span class=identifier>World</span><span class=special>& </span><span class=identifier>w</span><span class=special>)
|
||||
{
|
||||
</span><span class=keyword>return </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>msg</span><span class=special>;
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
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>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>add_method</span><span class=special>(</span><span class=identifier>W</span><span class=special>, </span><span class=string>"greet"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Notice also that then you can rename it, set its policy, just like a regular
|
||||
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>
|
||||
<p>
|
||||
Now from Python:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>import </span><span class=identifier>hello
|
||||
</span><span class=special>>>> </span><span class=identifier>w </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>()
|
||||
>>> </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>set</span><span class=special>(</span><span class=literal>'Ni'</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>'Ni'
|
||||
</span><span class=special>>>> </span><span class=identifier>print </span><span class=literal>'Oh no! The knights who say Ni!'
|
||||
</span><span class=identifier>Oh </span><span class=identifier>no</span><span class=special>! </span><span class=identifier>The </span><span class=identifier>knights </span><span class=identifier>who </span><span class=identifier>say </span><span class=identifier>Ni</span><span class=special>!
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="global_variables.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="inserting_code.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,85 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Exporting An Entire Header</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="wrappers.html">
|
||||
<link rel="next" href="smart_pointers.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Exporting An Entire Header</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Pyste also supports a mechanism to export all declarations found in a header
|
||||
file. Suppose again our file, <tt>hello.h</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>World
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {}
|
||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>show</span><span class=special>(</span><span class=identifier>choice </span><span class=identifier>c</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"value: " </span><span class=special><< (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; }
|
||||
</span></pre></code>
|
||||
<p>
|
||||
You can just use the <tt>AllFromHeader</tt> construct:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>hello </span><span class=special>= </span><span class=identifier>AllFromHeader</span><span class=special>(</span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
this will export all the declarations found in <tt>hello.h</tt>, which is equivalent
|
||||
to write:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=string>"show"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that you can still use the functions <tt>rename</tt>, <tt>set_policy</tt>, <tt>exclude</tt>, etc. Just access
|
||||
the members of the header object like this:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>hello</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>"Greet"</span><span class=special>)
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>hello</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>"Set"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img> <b>AllFromHeader is broken</b> in some cases. Until it is fixed,
|
||||
use at you own risk.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,49 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Global Variables</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="smart_pointers.html">
|
||||
<link rel="next" href="adding_new_methods.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Global Variables</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
To export global variables, use the <tt>Var</tt> construct:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Var</span><span class=special>(</span><span class=string>"myglobal"</span><span class=special>, </span><span class=string>"foo.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Beware of non-const global variables: changes in Python won't reflect in C++!
|
||||
If you really must change them in Python, you will have to write some accessor
|
||||
functions, and export those.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,72 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Inserting Code</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="adding_new_methods.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Inserting Code</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="adding_new_methods.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
You can insert arbitrary code in the generated cpps, just use the functions
|
||||
<tt>declaration_code</tt> and <tt>module_code</tt>. This will insert the given string in the
|
||||
respective sections. Example:</p>
|
||||
<code><pre>
|
||||
##<span class=identifier>file </span><span class=identifier>A</span><span class=special>.</span><span class=identifier>pyste
|
||||
</span><span class=identifier>Class</span><span class=special>(</span><span class=string>"A"</span><span class=special>, </span><span class=string>"A.h"</span><span class=special>)
|
||||
</span><span class=identifier>declaration_code</span><span class=special>(</span><span class=string>"/* declaration_code() comes here */\n"</span><span class=special>)
|
||||
</span><span class=identifier>module_code</span><span class=special>(</span><span class=string>"/* module_code() comes here */\n"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Will generate:</p>
|
||||
<code><pre>
|
||||
<span class=comment>// Includes ====================================================================
|
||||
</span><span class=preprocessor>#include </span><span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>>
|
||||
|
||||
// </span><span class=identifier>Using </span><span class=special>=======================================================================
|
||||
</span><span class=keyword>using </span><span class=keyword>namespace </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>python</span><span class=special>;
|
||||
|
||||
// </span><span class=identifier>Declarations </span><span class=special>================================================================
|
||||
|
||||
/* </span><span class=identifier>declaration_code</span><span class=special>() </span><span class=identifier>comes </span><span class=identifier>here </span><span class=special>*/
|
||||
|
||||
// </span><span class=identifier>Module </span><span class=special>======================================================================
|
||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>A</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>class_</span><span class=special>< </span><span class=identifier>A </span><span class=special>>(</span><span class=string>"A"</span><span class=special>, </span><span class=identifier>init</span><span class=special>< >())
|
||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>init</span><span class=special>< </span><span class=keyword>const </span><span class=identifier>A</span><span class=special>& >())
|
||||
;
|
||||
|
||||
/* </span><span class=identifier>module_code</span><span class=special>() </span><span class=identifier>comes </span><span class=identifier>here </span><span class=special>*/
|
||||
}
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="adding_new_methods.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,73 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Introduction</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="next" href="running_pyste.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Introduction</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="running_pyste.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="what_is_pyste_"></a><h2>What is Pyste?</h2><p>
|
||||
Pyste is a <a href="../../index.html">
|
||||
Boost.Python</a> code generator. The user specifies the classes and
|
||||
functions to be exported using a simple <i>interface file</i>, which following the
|
||||
<a href="../../index.html">
|
||||
Boost.Python</a>'s philosophy, is simple Python code. Pyste then uses <a href="http://www.gccxml.org">
|
||||
GCCXML</a> to
|
||||
parse all the headers and extract the necessary information to automatically
|
||||
generate C++ code.</p>
|
||||
<a name="example"></a><h2>Example</h2><p>
|
||||
Let's borrow the class <tt>World</tt> from the <a href="../../doc/tutorial/doc/html/python/exposing.html">
|
||||
tutorial</a>: </p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>World
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Here's the interface file for it, named <tt>world.pyste</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"world.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
and that's it!</p>
|
||||
<p>
|
||||
The next step is invoke Pyste in the command-line:</p>
|
||||
<code><pre>python pyste.py --module=hello world.pyste</pre></code><p>
|
||||
this will create a file "<tt>hello.cpp</tt>" in the directory where the command was
|
||||
run. </p>
|
||||
<p>
|
||||
Pyste supports the following features:</p>
|
||||
<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both "free" enums and class enums)</li><li>Nested Classes</li><li>Support for <tt>boost::shared_ptr</tt> and <tt>std::auto_ptr</tt></li><li>Global Variables</li></ul><table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="running_pyste.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,90 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Policies</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="renaming_and_excluding.html">
|
||||
<link rel="next" href="templates.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Policies</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="renaming_and_excluding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="templates.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Even thought Pyste can identify various elements in the C++ code, like virtual
|
||||
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/html/python/functions.html#python.call_policies">
|
||||
tutorial</a>.</p>
|
||||
<p>
|
||||
The policies in Pyste are named exactly as in <a href="../../index.html">
|
||||
Boost.Python</a>, only the syntax is
|
||||
slightly different. For instance, this policy:</p>
|
||||
<code><pre>
|
||||
<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>
|
||||
becomes in Pyste: </p>
|
||||
<code><pre>
|
||||
<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 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>))
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<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>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img>
|
||||
Note that for functions that return <tt>const T&</tt>, the policy
|
||||
<tt>return_value_policy<copy_const_reference>()</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.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="renaming_and_excluding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="templates.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,664 +0,0 @@
|
||||
[doc Pyste Documentation]
|
||||
|
||||
[/ Copyright 2003 Bruno da Silva de Oliveira and Joel de Guzman.
|
||||
Distributed under the Boost Software License, Version 1.0. (See
|
||||
accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[def GCCXML [@http://www.gccxml.org GCCXML]]
|
||||
[def Boost.Python [@../../index.html Boost.Python]]
|
||||
|
||||
[page Introduction]
|
||||
|
||||
[h2 What is Pyste?]
|
||||
|
||||
Pyste is a Boost.Python code generator. The user specifies the classes and
|
||||
functions to be exported using a simple ['interface file], which following the
|
||||
Boost.Python's philosophy, is simple Python code. Pyste then uses GCCXML to
|
||||
parse all the headers and extract the necessary information to automatically
|
||||
generate C++ code.
|
||||
|
||||
[h2 Example]
|
||||
|
||||
Let's borrow the class [^World] from the [@../../doc/tutorial/doc/exposing_classes.html tutorial]:
|
||||
|
||||
struct World
|
||||
{
|
||||
void set(std::string msg) { this->msg = msg; }
|
||||
std::string greet() { return msg; }
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
Here's the interface file for it, named [^world.pyste]:
|
||||
|
||||
Class("World", "world.h")
|
||||
|
||||
and that's it!
|
||||
|
||||
The next step is invoke Pyste in the command-line:
|
||||
|
||||
[pre python pyste.py --module=hello world.pyste]
|
||||
|
||||
this will create a file "[^hello.cpp]" in the directory where the command was
|
||||
run.
|
||||
|
||||
Pyste supports the following features:
|
||||
|
||||
* Functions
|
||||
* Classes
|
||||
* Class Templates
|
||||
* Virtual Methods
|
||||
* Overloading
|
||||
* Attributes
|
||||
* Enums (both "free" enums and class enums)
|
||||
* Nested Classes
|
||||
* Support for [^boost::shared_ptr] and [^std::auto_ptr]
|
||||
* Global Variables
|
||||
|
||||
[page Running Pyste]
|
||||
|
||||
To run Pyste, you will need:
|
||||
|
||||
* Python 2.2, available at [@http://www.python.org python's website].
|
||||
* The great [@http://effbot.org elementtree] library, from Fredrik Lundh.
|
||||
* The excellent GCCXML, from Brad King.
|
||||
|
||||
Installation for the tools is available in their respective webpages.
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] GCCXML must be accessible in the PATH environment variable, so
|
||||
that Pyste can call it. How to do this varies from platform to platform.
|
||||
]
|
||||
|
||||
[h2 Ok, now what?]
|
||||
|
||||
Well, now let's fire it up:
|
||||
|
||||
[pre
|
||||
'''
|
||||
>python pyste.py
|
||||
|
||||
Pyste version 0.9.26
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> The name of the module that will be generated;
|
||||
defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> Add an include path
|
||||
-D <symbol> Define symbol
|
||||
--multiple Create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out=<name> Specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using Do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> Set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug Writes the xml for each file parsed in the current
|
||||
directory
|
||||
--cache-dir=<dir> Directory for cache files (speeds up future runs)
|
||||
--only-create-cache Recreates all caches (doesn't generate code).
|
||||
--generate-main Generates the _main.cpp file (in multiple mode)
|
||||
--file-list A file with one pyste file per line. Use as a
|
||||
substitute for passing the files in the command
|
||||
line.
|
||||
-h, --help Print this help and exit
|
||||
-v, --version Print version information
|
||||
|
||||
'''
|
||||
]
|
||||
|
||||
Options explained:
|
||||
|
||||
The [^-I] and [^-D] are preprocessor flags, which are needed by GCCXML to parse
|
||||
the header files correctly and by Pyste to find the header files declared in the
|
||||
interface files.
|
||||
|
||||
[^--out] names the output file (default: [^<module>.cpp]), or in multiple mode,
|
||||
names a output directory for the files (default: [^<module>]).
|
||||
|
||||
[^--no-using] tells Pyste to don't declare "[^using namespace boost;]" in the
|
||||
generated cpp, using the namespace boost::python explicitly in all declarations.
|
||||
Use only if you're having a name conflict in one of the files.
|
||||
|
||||
Use [^--pyste-ns] to change the namespace where new types are declared (for
|
||||
instance, the virtual wrappers). Use only if you are having any problems. By
|
||||
default, Pyste uses the empty namespace.
|
||||
|
||||
[^--debug] will write in the current directory a xml file as outputted by GCCXML
|
||||
for each header parsed. Useful for bug reports.
|
||||
|
||||
[^--file-list] names a file where each line points to a Pyste file. Use this instead
|
||||
to pass the pyste files if you have a lot of them and your shell has some command line
|
||||
size limit.
|
||||
|
||||
The other options are explained below, in [@#multiple_mode [*Multiple Mode]] and
|
||||
[@#cache [*Cache]].
|
||||
|
||||
[^-h, --help, -v, --version] are self-explaining, I believe. ;)
|
||||
|
||||
So, the usage is simple enough:
|
||||
|
||||
[pre >python pyste.py --module=mymodule file.pyste file2.pyste ...]
|
||||
|
||||
will generate a file [^mymodule.cpp] in the same dir where the command was
|
||||
executed. Now you can compile the file using the same instructions of the
|
||||
[@../../doc/tutorial/doc/building_hello_world.html tutorial].
|
||||
|
||||
[h2 Wait... how do I set those I and D flags?]
|
||||
|
||||
Don't worry: normally GCCXML is already configured correctly for your plataform,
|
||||
so the search path to the standard libraries and the standard defines should
|
||||
already be set. You only have to set the paths to other libraries that your code
|
||||
needs, like Boost, for example.
|
||||
|
||||
Plus, Pyste automatically uses the contents of the environment variable
|
||||
[^INCLUDE] if it exists. Visual C++ users should run the [^Vcvars32.bat] file,
|
||||
which for Visual C++ 6 is normally located at:
|
||||
|
||||
C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat
|
||||
|
||||
with that, you should have little trouble setting up the flags.
|
||||
|
||||
[blurb [$theme/note.gif][*A note about Psyco][br][br]
|
||||
Although you don't have to install [@http://psyco.sourceforge.net/ Psyco] to
|
||||
use Pyste, if you do, Pyste will make use of it to speed up the wrapper
|
||||
generation. Speed ups of 30% can be achieved, so it's highly recommended.
|
||||
]
|
||||
|
||||
|
||||
[h2 Multiple Mode]
|
||||
|
||||
The multiple mode is useful in large projects, where the presence of multiple
|
||||
classes in a single file makes the compilation unpractical (excessive memory
|
||||
usage, mostly).
|
||||
|
||||
The solution is make Pyste generate multiple files, more specifically one cpp
|
||||
file for each Pyste file. This files will contain a function named after the
|
||||
file, for instance Export_MyPysteFile, which will contain all the code to export
|
||||
the classes, enums, etc. You can pass as much files as you want this way:
|
||||
|
||||
[pre >python pyste.py --module=mymodule file1.pyste file2.pyste]
|
||||
|
||||
This will create the files [^mymodule/file1.cpp] and [^mymodule/file2.cpp]. You
|
||||
can then later do:
|
||||
|
||||
[pre >python pyste.py --module=mymodule file3.pyste]
|
||||
|
||||
and [^mymodule/file3.cpp] will be generated.
|
||||
|
||||
But compiling and linking this files won't be sufficient to generate your
|
||||
extension. You have to also generate a file named [^main.cpp]; call pyste with
|
||||
[*all] the Pyste files of your extension, and use the [^--generate-main] option:
|
||||
|
||||
[pre >python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste]
|
||||
|
||||
Now compile and link all this files together and your extension is ready for
|
||||
use.
|
||||
|
||||
[h2 Cache]
|
||||
|
||||
Pyste now supports a form of cache, which is a way to speed up the code
|
||||
generation. Most of the time that Pyste takes to generate the code comes from
|
||||
having to execute GCCXML (since being a front-end to GCC, it has to compile the
|
||||
header files) and reading back the XML generated.
|
||||
|
||||
When you use the [^--cache-dir=<dir>] option, Pyste will dump in the specified
|
||||
directory the generated XMLs to a file named after the Pyste file, with the
|
||||
extension [^.pystec]. The next time you run with this option, Pyste will use
|
||||
the cache, instead of calling GCCXML again:
|
||||
|
||||
[pre >python pyste.py --module=mymodule --cache-dir=cache file1.pyste]
|
||||
|
||||
Will generate [^file1.cpp] and [^cache/file1.pystec]. Next time you execute
|
||||
this command, the cache file will be used. Note that Pyste doesn't do any check
|
||||
to ensure that the cache is up to date, but you can configure your build system to do that for you.
|
||||
|
||||
When you run Pyste with [^--only-create-cache], all the cache files will be
|
||||
created again, but no code will be generated.
|
||||
|
||||
[page The Interface Files]
|
||||
|
||||
The interface files are the heart of Pyste. The user creates one or more
|
||||
interface files declaring the classes and functions he wants to export, and then
|
||||
invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
cpp file with Boost.Python code, with all the classes and functions exported.
|
||||
|
||||
Besides declaring the classes and functions, the user has a number of other
|
||||
options, like renaming e excluding classes and member functionis. Those are
|
||||
explained later on.
|
||||
|
||||
[h2 Basics]
|
||||
|
||||
Suppose we have a class and some functions that we want to expose to Python
|
||||
declared in the header [^hello.h]:
|
||||
|
||||
struct World
|
||||
{
|
||||
World(std::string msg): msg(msg) {}
|
||||
void set(std::string msg) { this->msg = msg; }
|
||||
std::string greet() { return msg; }
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
enum choice { red, blue };
|
||||
|
||||
namespace test {
|
||||
|
||||
void show(choice c) { std::cout << "value: " << (int)c << std::endl; }
|
||||
|
||||
}
|
||||
|
||||
We create a file named [^hello.pyste] and create instances of the classes
|
||||
[^Function], [^Class] and [^Enum]:
|
||||
|
||||
Function("test::show", "hello.h")
|
||||
Class("World", "hello.h")
|
||||
Enum("choice", "hello.h")
|
||||
|
||||
That will expose the class, the free function and the enum found in [^hello.h].
|
||||
|
||||
[h2 Inheritance]
|
||||
|
||||
Pyste automatically generates the correct code (specifying [^bases<>] in the
|
||||
[^class_] declaration) [*if] the Class() function that exports the base classes
|
||||
and their children are in the same Pyste file. If that's not the case, you have
|
||||
to indicate that there's a relationship between the Pyste files using the
|
||||
[^Import] function specifying the other Pyste file.
|
||||
|
||||
Suppose we have two classes, [^A] and [^B], and A is a base class for B. We
|
||||
create two Pyste files:
|
||||
|
||||
[^A.pyste]:
|
||||
|
||||
Class("A", "A.h")
|
||||
|
||||
[^B.pyste]:
|
||||
|
||||
Import("A.pyste")
|
||||
Class("B", "B.h")
|
||||
|
||||
Note that we specify that [^B] needs to know about [^A] to be properly exported.
|
||||
|
||||
[page:1 Renaming and Excluding]
|
||||
|
||||
You can easily rename functions, classes, member functions, attributes, etc. Just use the
|
||||
function [^rename], like this:
|
||||
|
||||
World = Class("World", "hello.h")
|
||||
rename(World, "IWorld")
|
||||
show = Function("choice", "hello.h")
|
||||
rename(show, "Show")
|
||||
|
||||
You can rename member functions and attributes using this syntax:
|
||||
|
||||
rename(World.greet, "Greet")
|
||||
rename(World.set, "Set")
|
||||
choice = Enum("choice", "hello.h")
|
||||
rename(choice.red, "Red")
|
||||
rename(choice.blue, "Blue")
|
||||
|
||||
You can exclude functions, classes, member functions, attributes, etc, in the same way,
|
||||
with the function [^exclude]:
|
||||
|
||||
exclude(World.greet)
|
||||
exclude(World.msg)
|
||||
|
||||
To access the operators of a class, access the member [^operator] like this
|
||||
(supposing that [^C] is a class being exported):
|
||||
|
||||
exclude(C.operator['+'])
|
||||
exclude(C.operator['*'])
|
||||
exclude(C.operator['<<'])
|
||||
|
||||
The string inside the brackets is the same as the name of the operator in C++.[br]
|
||||
|
||||
[h2 Virtual Member Functions]
|
||||
|
||||
Pyste automatically generates wrappers for virtual member functions, but you may
|
||||
want to disable this behaviour (for performance reasons, for instance) if you do
|
||||
not plan to override the functions in Python. To do this, use the function
|
||||
[^final]:
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
final(C.foo) # C::foo is a virtual member function
|
||||
|
||||
No virtual wrapper code will be generated for the virtual member function
|
||||
C::foo that way.
|
||||
|
||||
[page:1 Policies]
|
||||
|
||||
Even thought Pyste can identify various elements in the C++ code, like virtual
|
||||
member functions, attributes, and so on, one thing that it can't do is to
|
||||
guess the semantics of functions that return pointers or references. In this
|
||||
case, the user must manually specify the policy. Policies are explained in the
|
||||
[@../../doc/tutorial/doc/call_policies.html tutorial].
|
||||
|
||||
The policies in Pyste are named exactly as in Boost.Python, only the syntax is
|
||||
slightly different. For instance, this policy:
|
||||
|
||||
return_internal_reference<1, with_custodian_and_ward<1, 2> >()
|
||||
|
||||
becomes in Pyste:
|
||||
|
||||
return_internal_reference(1, with_custodian_and_ward(1, 2))
|
||||
|
||||
The user can specify policies for functions and virtual member functions with
|
||||
the [^set_policy] function:
|
||||
|
||||
set_policy(f, return_internal_reference())
|
||||
set_policy(C.foo, return_value_policy(manage_new_object))
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] [*What if a function or member function needs a policy and
|
||||
the user doesn't set one?][br][br] If a function needs a policy and one
|
||||
was not set, Pyste will issue a error. The user should then go in the
|
||||
interface file and set the policy for it, otherwise the generated cpp won't
|
||||
compile.
|
||||
]
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]
|
||||
Note that for functions that return [^const T&], the policy
|
||||
[^return_value_policy<copy_const_reference>()] wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
]
|
||||
|
||||
[page:1 Templates]
|
||||
|
||||
Template classes can easily be exported too, but you can't export the template
|
||||
itself... you have to export instantiations of it! So, if you want to export a
|
||||
[^std::vector], you will have to export vectors of int, doubles, etc.
|
||||
|
||||
Suppose we have this code:
|
||||
|
||||
template <class T>
|
||||
struct Point
|
||||
{
|
||||
T x;
|
||||
T y;
|
||||
};
|
||||
|
||||
And we want to export [^Point]s of int and double:
|
||||
|
||||
Point = Template("Point", "point.h")
|
||||
Point("int")
|
||||
Point("double")
|
||||
|
||||
Pyste will assign default names for each instantiation. In this example, those
|
||||
would be "[^Point_int]" and "[^Point_double]", but most of the time users will want to
|
||||
rename the instantiations:
|
||||
|
||||
Point("int", "IPoint") // renames the instantiation
|
||||
double_inst = Point("double") // another way to do the same
|
||||
rename(double_inst, "DPoint")
|
||||
|
||||
Note that you can rename, exclude, set policies, etc, in the [^Template] object
|
||||
like you would do with a [^Function] or a [^Class]. This changes affect all
|
||||
[*future] instantiations:
|
||||
|
||||
Point = Template("Point", "point.h")
|
||||
Point("float", "FPoint") // will have x and y as data members
|
||||
rename(Point.x, "X")
|
||||
rename(Point.y, "Y")
|
||||
Point("int", "IPoint") // will have X and Y as data members
|
||||
Point("double", "DPoint") // also will have X and Y as data member
|
||||
|
||||
If you want to change a option of a particular instantiation, you can do so:
|
||||
|
||||
Point = Template("Point", "point.h")
|
||||
Point("int", "IPoint")
|
||||
d_inst = Point("double", "DPoint")
|
||||
rename(d_inst.x, "X") // only DPoint is affect by this renames,
|
||||
rename(d_inst.y, "Y") // IPoint stays intact
|
||||
|
||||
[blurb [$theme/note.gif] [*What if my template accepts more than one type?]
|
||||
[br][br]
|
||||
When you want to instantiate a template with more than one type, you can pass
|
||||
either a string with the types separated by whitespace, or a list of strings
|
||||
'''("int double" or ["int", "double"]''' would both work).
|
||||
]
|
||||
|
||||
[page:1 Wrappers]
|
||||
|
||||
Suppose you have this function:
|
||||
|
||||
std::vector<std::string> names();
|
||||
|
||||
But you don't want to [@../../doc/v2/faq.html#question2 to export std::vector<std::string>],
|
||||
you want this function to return a python list of strings. Boost.Python has
|
||||
excellent support for things like that:
|
||||
|
||||
list names_wrapper()
|
||||
{
|
||||
list result;
|
||||
// call original function
|
||||
vector<string> v = names();
|
||||
// put all the strings inside the python list
|
||||
vector<string>::iterator it;
|
||||
for (it = v.begin(); it != v.end(); ++it){
|
||||
result.append(*it);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(test)
|
||||
{
|
||||
def("names", &names_wrapper);
|
||||
}
|
||||
|
||||
Nice heh? Pyste supports this mechanism too. You declare the [^names_wrapper]
|
||||
function in a header named "[^test_wrappers.h]" and in the interface file:
|
||||
|
||||
Include("test_wrappers.h")
|
||||
names = Function("names", "test.h")
|
||||
set_wrapper(names, "names_wrapper")
|
||||
|
||||
You can optionally declare the function in the interface file itself:
|
||||
|
||||
names_wrapper = Wrapper("names_wrapper",
|
||||
"""
|
||||
list names_wrapper()
|
||||
{
|
||||
// code to call name() and convert the vector to a list...
|
||||
}
|
||||
""")
|
||||
names = Function("names", "test.h")
|
||||
set_wrapper(names, names_wrapper)
|
||||
|
||||
The same mechanism can be used with member functions too. Just remember that
|
||||
the first parameter of wrappers for member functions is a pointer to the
|
||||
class, as in:
|
||||
|
||||
struct C
|
||||
{
|
||||
std::vector<std::string> names();
|
||||
}
|
||||
|
||||
list names_wrapper(C* c)
|
||||
{
|
||||
// same as before, calling c->names() and converting result to a list
|
||||
}
|
||||
|
||||
And then in the interface file:
|
||||
|
||||
C = Class("C", "test.h")
|
||||
set_wrapper(C.names, "names_wrapper")
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]Even though Boost.Python accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a [*pointer]. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual member function.
|
||||
]
|
||||
|
||||
[page:1 Exporting An Entire Header]
|
||||
|
||||
Pyste also supports a mechanism to export all declarations found in a header
|
||||
file. Suppose again our file, [^hello.h]:
|
||||
|
||||
struct World
|
||||
{
|
||||
World(std::string msg): msg(msg) {}
|
||||
void set(std::string msg) { this->msg = msg; }
|
||||
std::string greet() { return msg; }
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
enum choice { red, blue };
|
||||
|
||||
void show(choice c) { std::cout << "value: " << (int)c << std::endl; }
|
||||
|
||||
You can just use the [^AllFromHeader] construct:
|
||||
|
||||
hello = AllFromHeader("hello.h")
|
||||
|
||||
this will export all the declarations found in [^hello.h], which is equivalent
|
||||
to write:
|
||||
|
||||
Class("World", "hello.h")
|
||||
Enum("choice", "hello.h")
|
||||
Function("show", "hello.h")
|
||||
|
||||
Note that you can still use the functions [^rename], [^set_policy], [^exclude], etc. Just access
|
||||
the members of the header object like this:
|
||||
|
||||
rename(hello.World.greet, "Greet")
|
||||
exclude(hello.World.set, "Set")
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] [*AllFromHeader is broken] in some cases. Until it is fixed,
|
||||
use at you own risk.
|
||||
]
|
||||
|
||||
|
||||
[page:1 Smart Pointers]
|
||||
|
||||
Pyste for now has manual support for smart pointers. Suppose:
|
||||
|
||||
struct C
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
boost::shared_ptr<C> newC(int value)
|
||||
{
|
||||
boost::shared_ptr<C> c( new C() );
|
||||
c->value = value;
|
||||
return c;
|
||||
}
|
||||
|
||||
void printC(boost::shared_ptr<C> c)
|
||||
{
|
||||
std::cout << c->value << std::endl;
|
||||
}
|
||||
|
||||
To make [^newC] and [^printC] work correctly, you have to tell Pyste that a
|
||||
convertor for [^boost::shared_ptr<C>] is needed.
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
use_shared_ptr(C)
|
||||
Function('newC', 'C.h')
|
||||
Function('printC', 'C.h')
|
||||
|
||||
For [^std::auto_ptr]'s, use the function [^use_auto_ptr].
|
||||
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.
|
||||
|
||||
[h2 Holders]
|
||||
|
||||
If only the converter for the smart pointers is not enough and you need to
|
||||
specify the smart pointer as the holder for a class, use the functions
|
||||
[^hold_with_shared_ptr] and [^hold_with_auto_ptr]:
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
hold_with_shared_ptr(C)
|
||||
Function('newC', 'C.h')
|
||||
Function('printC', 'C.h')
|
||||
|
||||
[page:1 Global Variables]
|
||||
|
||||
To export global variables, use the [^Var] construct:
|
||||
|
||||
Var("myglobal", "foo.h")
|
||||
|
||||
Beware of non-const global variables: changes in Python won't reflect in C++!
|
||||
If you really must change them in Python, you will have to write some accessor
|
||||
functions, and export those.
|
||||
|
||||
|
||||
[page:1 Adding New Methods]
|
||||
|
||||
Suppose that you want to add a function to a class, turning it into a member
|
||||
function:
|
||||
|
||||
struct World
|
||||
{
|
||||
void set(std::string msg) { this->msg = msg; }
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
std::string greet(World& w)
|
||||
{
|
||||
return w.msg;
|
||||
}
|
||||
|
||||
Here, we want to make [^greet] work as a member function of the class [^World]. We do
|
||||
that using the [^add_method] construct:
|
||||
|
||||
W = Class("World", "hello.h")
|
||||
add_method(W, "greet")
|
||||
|
||||
Notice also that then you can rename it, set its policy, just like a regular
|
||||
member function:
|
||||
|
||||
rename(W.greet, 'Greet')
|
||||
|
||||
Now from Python:
|
||||
|
||||
>>> import hello
|
||||
>>> w = hello.World()
|
||||
>>> w.set('Ni')
|
||||
>>> w.greet()
|
||||
'Ni'
|
||||
>>> print 'Oh no! The knights who say Ni!'
|
||||
Oh no! The knights who say Ni!
|
||||
|
||||
|
||||
[page:1 Inserting Code]
|
||||
|
||||
You can insert arbitrary code in the generated cpps, just use the functions
|
||||
[^declaration_code] and [^module_code]. This will insert the given string in the
|
||||
respective sections. Example:
|
||||
|
||||
# file A.pyste
|
||||
Class("A", "A.h")
|
||||
declaration_code("/* declaration_code() comes here */\n")
|
||||
module_code("/* module_code() comes here */\n")
|
||||
|
||||
Will generate:
|
||||
|
||||
// Includes ====================================================================
|
||||
#include <boost/python.hpp>
|
||||
|
||||
// Using =======================================================================
|
||||
using namespace boost::python;
|
||||
|
||||
// Declarations ================================================================
|
||||
|
||||
/* declaration_code() comes here */
|
||||
|
||||
// Module ======================================================================
|
||||
BOOST_PYTHON_MODULE(A)
|
||||
{
|
||||
class_< A >("A", init< >())
|
||||
.def(init< const A& >())
|
||||
;
|
||||
|
||||
/* module_code() comes here */
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Renaming and Excluding</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="the_interface_files.html">
|
||||
<link rel="next" href="policies.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Renaming and Excluding</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="the_interface_files.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="policies.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
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>"World"</span><span class=special>, </span><span class=string>"hello.h"</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=string>"IWorld"</span><span class=special>)
|
||||
</span><span class=identifier>show </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>show</span><span class=special>, </span><span class=string>"Show"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<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>"Greet"</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>"Set"</span><span class=special>)
|
||||
</span><span class=identifier>choice </span><span class=special>= </span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>red</span><span class=special>, </span><span class=string>"Red"</span><span class=special>)
|
||||
</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>"Blue"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
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>)
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>msg</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
To access the operators of a class, access the member <tt>operator</tt> like this
|
||||
(supposing that <tt>C</tt> is a class being exported):</p>
|
||||
<code><pre>
|
||||
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'+'</span><span class=special>])
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'*'</span><span class=special>])
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'<<'</span><span class=special>])
|
||||
</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, for instance) 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>
|
||||
<td width="30"><a href="the_interface_files.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="policies.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,200 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Running Pyste</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="introduction.html">
|
||||
<link rel="next" href="the_interface_files.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Running Pyste</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="the_interface_files.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
To run Pyste, you will need:</p>
|
||||
<ul><li>Python 2.2, available at <a href="http://www.python.org">
|
||||
python's website</a>.</li><li>The great <a href="http://effbot.org">
|
||||
elementtree</a> library, from Fredrik Lundh.</li><li>The excellent <a href="http://www.gccxml.org">
|
||||
GCCXML</a>, from Brad King.</li></ul><p>
|
||||
Installation for the tools is available in their respective webpages.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img> <a href="http://www.gccxml.org">
|
||||
GCCXML</a> must be accessible in the PATH environment variable, so
|
||||
that Pyste can call it. How to do this varies from platform to platform.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="ok__now_what_"></a><h2>Ok, now what?</h2><p>
|
||||
Well, now let's fire it up:</p>
|
||||
<code><pre>
|
||||
|
||||
>python pyste.py
|
||||
|
||||
Pyste version 0.9.26
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> The name of the module that will be generated;
|
||||
defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> Add an include path
|
||||
-D <symbol> Define symbol
|
||||
--multiple Create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out=<name> Specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using Do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> Set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug Writes the xml for each file parsed in the current
|
||||
directory
|
||||
--cache-dir=<dir> Directory for cache files (speeds up future runs)
|
||||
--only-create-cache Recreates all caches (doesn't generate code).
|
||||
--generate-main Generates the _main.cpp file (in multiple mode)
|
||||
--file-list A file with one pyste file per line. Use as a
|
||||
substitute for passing the files in the command
|
||||
line.
|
||||
-h, --help Print this help and exit
|
||||
-v, --version Print version information
|
||||
|
||||
|
||||
</pre></code><p>
|
||||
Options explained:</p>
|
||||
<p>
|
||||
The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by <a href="http://www.gccxml.org">
|
||||
GCCXML</a> to parse
|
||||
the header files correctly and by Pyste to find the header files declared in the
|
||||
interface files.</p>
|
||||
<p>
|
||||
<tt>--out</tt> names the output file (default: <tt><module>.cpp</tt>), or in multiple mode,
|
||||
names a output directory for the files (default: <tt><module></tt>).</p>
|
||||
<p>
|
||||
<tt>--no-using</tt> tells Pyste to don't declare "<tt>using namespace boost;</tt>" in the
|
||||
generated cpp, using the namespace boost::python explicitly in all declarations.
|
||||
Use only if you're having a name conflict in one of the files.</p>
|
||||
<p>
|
||||
Use <tt>--pyste-ns</tt> to change the namespace where new types are declared (for
|
||||
instance, the virtual wrappers). Use only if you are having any problems. By
|
||||
default, Pyste uses the empty namespace.</p>
|
||||
<p>
|
||||
<tt>--debug</tt> will write in the current directory a xml file as outputted by <a href="http://www.gccxml.org">
|
||||
GCCXML</a>
|
||||
for each header parsed. Useful for bug reports.</p>
|
||||
<p>
|
||||
<tt>--file-list</tt> names a file where each line points to a Pyste file. Use this instead
|
||||
to pass the pyste files if you have a lot of them and your shell has some command line
|
||||
size limit.</p>
|
||||
<p>
|
||||
The other options are explained below, in <a href="#multiple_mode">
|
||||
<b>Multiple Mode</b></a> and
|
||||
<a href="#cache">
|
||||
<b>Cache</b></a>.</p>
|
||||
<p>
|
||||
<tt>-h, --help, -v, --version</tt> are self-explaining, I believe. ;)</p>
|
||||
<p>
|
||||
So, the usage is simple enough:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule file.pyste file2.pyste ...</pre></code><p>
|
||||
will generate a file <tt>mymodule.cpp</tt> in the same dir where the command was
|
||||
executed. Now you can compile the file using the same instructions of the
|
||||
<a href="../../doc/tutorial/doc/html/python/hello.html">
|
||||
tutorial</a>. </p>
|
||||
<a name="wait____how_do_i_set_those_i_and_d_flags_"></a><h2>Wait... how do I set those I and D flags?</h2><p>
|
||||
Don't worry: normally <a href="http://www.gccxml.org">
|
||||
GCCXML</a> is already configured correctly for your plataform,
|
||||
so the search path to the standard libraries and the standard defines should
|
||||
already be set. You only have to set the paths to other libraries that your code
|
||||
needs, like Boost, for example.</p>
|
||||
<p>
|
||||
Plus, Pyste automatically uses the contents of the environment variable
|
||||
<tt>INCLUDE</tt> if it exists. Visual C++ users should run the <tt>Vcvars32.bat</tt> file,
|
||||
which for Visual C++ 6 is normally located at:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>C</span><span class=special>:\</span><span class=identifier>Program </span><span class=identifier>Files</span><span class=special>\</span><span class=identifier>Microsoft </span><span class=identifier>Visual </span><span class=identifier>Studio</span><span class=special>\</span><span class=identifier>VC98</span><span class=special>\</span><span class=identifier>bin</span><span class=special>\</span><span class=identifier>Vcvars32</span><span class=special>.</span><span class=identifier>bat
|
||||
</span></pre></code>
|
||||
<p>
|
||||
with that, you should have little trouble setting up the flags.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif"></img><b>A note about Psyco</b><br><br>
|
||||
Although you don't have to install <a href="http://psyco.sourceforge.net/">
|
||||
Psyco</a> to
|
||||
use Pyste, if you do, Pyste will make use of it to speed up the wrapper
|
||||
generation. Speed ups of 30% can be achieved, so it's highly recommended.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="multiple_mode"></a><h2>Multiple Mode</h2><p>
|
||||
The multiple mode is useful in large projects, where the presence of multiple
|
||||
classes in a single file makes the compilation unpractical (excessive memory
|
||||
usage, mostly). </p>
|
||||
<p>
|
||||
The solution is make Pyste generate multiple files, more specifically one cpp
|
||||
file for each Pyste file. This files will contain a function named after the
|
||||
file, for instance Export_MyPysteFile, which will contain all the code to export
|
||||
the classes, enums, etc. You can pass as much files as you want this way:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule file1.pyste file2.pyste</pre></code><p>
|
||||
This will create the files <tt>mymodule/file1.cpp</tt> and <tt>mymodule/file2.cpp</tt>. You
|
||||
can then later do:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule file3.pyste</pre></code><p>
|
||||
and <tt>mymodule/file3.cpp</tt> will be generated.</p>
|
||||
<p>
|
||||
But compiling and linking this files won't be sufficient to generate your
|
||||
extension. You have to also generate a file named <tt>main.cpp</tt>; call pyste with
|
||||
<b>all</b> the Pyste files of your extension, and use the <tt>--generate-main</tt> option:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule --generate-main file1.pyste file2.pyste file3.pyste</pre></code><p>
|
||||
Now compile and link all this files together and your extension is ready for
|
||||
use.</p>
|
||||
<a name="cache"></a><h2>Cache</h2><p>
|
||||
Pyste now supports a form of cache, which is a way to speed up the code
|
||||
generation. Most of the time that Pyste takes to generate the code comes from
|
||||
having to execute <a href="http://www.gccxml.org">
|
||||
GCCXML</a> (since being a front-end to GCC, it has to compile the
|
||||
header files) and reading back the XML generated. </p>
|
||||
<p>
|
||||
When you use the <tt>--cache-dir=<dir></tt> option, Pyste will dump in the specified
|
||||
directory the generated XMLs to a file named after the Pyste file, with the
|
||||
extension <tt>.pystec</tt>. The next time you run with this option, Pyste will use
|
||||
the cache, instead of calling <a href="http://www.gccxml.org">
|
||||
GCCXML</a> again:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule --cache-dir=cache file1.pyste</pre></code><p>
|
||||
Will generate <tt>file1.cpp</tt> and <tt>cache/file1.pystec</tt>. Next time you execute
|
||||
this command, the cache file will be used. Note that Pyste doesn't do any check
|
||||
to ensure that the cache is up to date, but you can configure your build system to do that for you.</p>
|
||||
<p>
|
||||
When you run Pyste with <tt>--only-create-cache</tt>, all the cache files will be
|
||||
created again, but no code will be generated.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="the_interface_files.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,84 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Smart Pointers</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="exporting_an_entire_header.html">
|
||||
<link rel="next" href="global_variables.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Smart Pointers</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Pyste for now has manual support for smart pointers. Suppose:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>C
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>newC</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>( </span><span class=keyword>new </span><span class=identifier>C</span><span class=special>() );
|
||||
</span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special>= </span><span class=identifier>value</span><span class=special>;
|
||||
</span><span class=keyword>return </span><span class=identifier>c</span><span class=special>;
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>printC</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
To make <tt>newC</tt> and <tt>printC</tt> work correctly, you have to tell Pyste that a
|
||||
convertor for <tt>boost::shared_ptr<C></tt> is needed.</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>use_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
For <tt>std::auto_ptr</tt>'s, use the function <tt>use_auto_ptr</tt>.</p>
|
||||
<p>
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.</p>
|
||||
<a name="holders"></a><h2>Holders</h2><p>
|
||||
If only the converter for the smart pointers is not enough and you need to
|
||||
specify the smart pointer as the holder for a class, use the functions
|
||||
<tt>hold_with_shared_ptr</tt> and <tt>hold_with_auto_ptr</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>hold_with_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,102 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Templates</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="policies.html">
|
||||
<link rel="next" href="wrappers.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Templates</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="wrappers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Template classes can easily be exported too, but you can't export the template
|
||||
itself... you have to export instantiations of it! So, if you want to export a
|
||||
<tt>std::vector</tt>, you will have to export vectors of int, doubles, etc.</p>
|
||||
<p>
|
||||
Suppose we have this code:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>class </span><span class=identifier>T</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>Point
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>T </span><span class=identifier>x</span><span class=special>;
|
||||
</span><span class=identifier>T </span><span class=identifier>y</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
And we want to export <tt>Point</tt>s of int and double:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>)
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>)
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Pyste will assign default names for each instantiation. In this example, those
|
||||
would be "<tt>Point_int</tt>" and "<tt>Point_double</tt>", but most of the time users will want to
|
||||
rename the instantiations:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>) // </span><span class=identifier>renames </span><span class=identifier>the </span><span class=identifier>instantiation
|
||||
</span><span class=identifier>double_inst </span><span class=special>= </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>) // </span><span class=identifier>another </span><span class=identifier>way </span><span class=identifier>to </span><span class=keyword>do </span><span class=identifier>the </span><span class=identifier>same
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>double_inst</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> object
|
||||
like you would do with a <tt>Function</tt> or a <tt>Class</tt>. This changes affect all
|
||||
<b>future</b> instantiations:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>)
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"float"</span><span class=special>, </span><span class=string>"FPoint"</span><span class=special>) // </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>x </span><span class=keyword>and </span><span class=identifier>y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>members
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>Point</span><span class=special>.</span><span class=identifier>x</span><span class=special>, </span><span class=string>"X"</span><span class=special>)
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>Point</span><span class=special>.</span><span class=identifier>y</span><span class=special>, </span><span class=string>"Y"</span><span class=special>)
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>) // </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>X </span><span class=keyword>and </span><span class=identifier>Y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>members
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>) // </span><span class=identifier>also </span><span class=identifier>will </span><span class=identifier>have </span><span class=identifier>X </span><span class=keyword>and </span><span class=identifier>Y </span><span class=identifier>as </span><span class=identifier>data </span><span class=identifier>member
|
||||
</span></pre></code>
|
||||
<p>
|
||||
If you want to change a option of a particular instantiation, you can do so:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Point </span><span class=special>= </span><span class=identifier>Template</span><span class=special>(</span><span class=string>"Point"</span><span class=special>, </span><span class=string>"point.h"</span><span class=special>)
|
||||
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>"int"</span><span class=special>, </span><span class=string>"IPoint"</span><span class=special>)
|
||||
</span><span class=identifier>d_inst </span><span class=special>= </span><span class=identifier>Point</span><span class=special>(</span><span class=string>"double"</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>)
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>d_inst</span><span class=special>.</span><span class=identifier>x</span><span class=special>, </span><span class=string>"X"</span><span class=special>) // </span><span class=identifier>only </span><span class=identifier>DPoint </span><span class=identifier>is </span><span class=identifier>affect </span><span class=identifier>by </span><span class=keyword>this </span><span class=identifier>renames</span><span class=special>,
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>d_inst</span><span class=special>.</span><span class=identifier>y</span><span class=special>, </span><span class=string>"Y"</span><span class=special>) // </span><span class=identifier>IPoint </span><span class=identifier>stays </span><span class=identifier>intact
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif"></img> <b>What if my template accepts more than one type?</b>
|
||||
<br><br>
|
||||
When you want to instantiate a template with more than one type, you can pass
|
||||
either a string with the types separated by whitespace, or a list of strings
|
||||
("int double" or ["int", "double"] would both work).
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="wrappers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,102 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>The Interface Files</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="running_pyste.html">
|
||||
<link rel="next" href="renaming_and_excluding.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>The Interface Files</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="running_pyste.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="renaming_and_excluding.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The interface files are the heart of Pyste. The user creates one or more
|
||||
interface files declaring the classes and functions he wants to export, and then
|
||||
invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
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 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>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>World
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {}
|
||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>namespace </span><span class=identifier>test </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>show</span><span class=special>(</span><span class=identifier>choice </span><span class=identifier>c</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"value: " </span><span class=special><< (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; }
|
||||
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
We create a file named <tt>hello.pyste</tt> and create instances of the classes
|
||||
<tt>Function</tt>, <tt>Class</tt> and <tt>Enum</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Function</span><span class=special>(</span><span class=string>"test::show"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
That will expose the class, the free function and the enum found in <tt>hello.h</tt>. </p>
|
||||
<a name="inheritance"></a><h2>Inheritance</h2><p>
|
||||
Pyste automatically generates the correct code (specifying <tt>bases<></tt> in the
|
||||
<tt>class_</tt> declaration) <b>if</b> the Class() function that exports the base classes
|
||||
and their children are in the same Pyste file. If that's not the case, you have
|
||||
to indicate that there's a relationship between the Pyste files using the
|
||||
<tt>Import</tt> function specifying the other Pyste file.</p>
|
||||
<p>
|
||||
Suppose we have two classes, <tt>A</tt> and <tt>B</tt>, and A is a base class for B. We
|
||||
create two Pyste files:</p>
|
||||
<p>
|
||||
<tt>A.pyste</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Class</span><span class=special>(</span><span class=string>"A"</span><span class=special>, </span><span class=string>"A.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
<tt>B.pyste</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Import</span><span class=special>(</span><span class=string>"A.pyste"</span><span class=special>)
|
||||
</span><span class=identifier>Class</span><span class=special>(</span><span class=string>"B"</span><span class=special>, </span><span class=string>"B.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that we specify that <tt>B</tt> needs to know about <tt>A</tt> to be properly exported.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="running_pyste.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="renaming_and_excluding.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
BIN
pyste/doc/theme/alert.gif
vendored
|
Before Width: | Height: | Size: 577 B |
BIN
pyste/doc/theme/arrow.gif
vendored
|
Before Width: | Height: | Size: 70 B |
BIN
pyste/doc/theme/bkd.gif
vendored
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
pyste/doc/theme/bkd2.gif
vendored
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
pyste/doc/theme/bulb.gif
vendored
|
Before Width: | Height: | Size: 944 B |
BIN
pyste/doc/theme/bullet.gif
vendored
|
Before Width: | Height: | Size: 152 B |
BIN
pyste/doc/theme/l_arr.gif
vendored
|
Before Width: | Height: | Size: 147 B |
BIN
pyste/doc/theme/l_arr_disabled.gif
vendored
|
Before Width: | Height: | Size: 91 B |
BIN
pyste/doc/theme/note.gif
vendored
|
Before Width: | Height: | Size: 151 B |
BIN
pyste/doc/theme/r_arr.gif
vendored
|
Before Width: | Height: | Size: 147 B |
BIN
pyste/doc/theme/r_arr_disabled.gif
vendored
|
Before Width: | Height: | Size: 91 B |
BIN
pyste/doc/theme/smiley.gif
vendored
|
Before Width: | Height: | Size: 879 B |
178
pyste/doc/theme/style.css
vendored
@@ -1,178 +0,0 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2003 Bruno da Silva de Oliveira
|
||||
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
=============================================================================*/
|
||||
|
||||
body
|
||||
{
|
||||
background-image: url(bkd.gif);
|
||||
background-color: #FFFFFF;
|
||||
margin: 1em 2em 1em 2em;
|
||||
}
|
||||
|
||||
h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; }
|
||||
h2 { font: 140% sans-serif; font-weight: bold; text-align: left; }
|
||||
h3 { font: 120% sans-serif; font-weight: bold; text-align: left; }
|
||||
h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
|
||||
pre
|
||||
{
|
||||
border-top: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
|
||||
padding-top: 2pt;
|
||||
padding-right: 2pt;
|
||||
padding-left: 2pt;
|
||||
padding-bottom: 2pt;
|
||||
|
||||
display: block;
|
||||
font-family: "courier new", courier, mono;
|
||||
background-color: #eeeeee; font-size: small
|
||||
}
|
||||
|
||||
code
|
||||
{
|
||||
font-family: "Courier New", Courier, mono;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
tt
|
||||
{
|
||||
display: inline;
|
||||
font-family: "Courier New", Courier, mono;
|
||||
color: #000099;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
p
|
||||
{
|
||||
text-align: justify;
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
ul
|
||||
{
|
||||
list-style-image: url(bullet.gif);
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
ol
|
||||
{
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
font-weight: bold;
|
||||
color: #003366;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover { color: #8080FF; }
|
||||
|
||||
.literal { color: #666666; font-style: italic}
|
||||
.keyword { color: #000099}
|
||||
.identifier {}
|
||||
.comment { font-style: italic; color: #990000}
|
||||
.special { color: #800040}
|
||||
.preprocessor { color: #FF0000}
|
||||
.string { font-style: italic; color: #666666}
|
||||
.copyright { color: #666666; font-size: small}
|
||||
.white_bkd { background-color: #FFFFFF}
|
||||
.dk_grey_bkd { background-color: #999999}
|
||||
.quotes { color: #666666; font-style: italic; font-weight: bold}
|
||||
|
||||
.note_box
|
||||
{
|
||||
display: block;
|
||||
|
||||
border-top: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
|
||||
padding-right: 12pt;
|
||||
padding-left: 12pt;
|
||||
padding-bottom: 12pt;
|
||||
padding-top: 12pt;
|
||||
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
background-color: #E2E9EF;
|
||||
font-size: small; text-align: justify
|
||||
}
|
||||
|
||||
.table_title
|
||||
{
|
||||
background-color: #648CCA;
|
||||
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF;
|
||||
font-weight: bold
|
||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
||||
}
|
||||
|
||||
.table_cells
|
||||
{
|
||||
background-color: #E2E9EF;
|
||||
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
font-size: small
|
||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
||||
}
|
||||
|
||||
.toc
|
||||
{
|
||||
DISPLAY: block;
|
||||
background-color: #E2E9EF
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
|
||||
border-top: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
|
||||
padding-top: 24pt;
|
||||
padding-right: 24pt;
|
||||
padding-left: 24pt;
|
||||
padding-bottom: 24pt;
|
||||
}
|
||||
|
||||
.toc_title
|
||||
{
|
||||
background-color: #648CCA;
|
||||
padding-top: 4px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
color: #FFFFFF;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.toc_cells
|
||||
{
|
||||
background-color: #E2E9EF;
|
||||
padding-top: 4px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
div.logo
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
BIN
pyste/doc/theme/u_arr.gif
vendored
|
Before Width: | Height: | Size: 170 B |
@@ -1,124 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Wrappers</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="templates.html">
|
||||
<link rel="next" href="exporting_an_entire_header.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Wrappers</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="templates.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Suppose you have this function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>();
|
||||
</span></pre></code>
|
||||
<p>
|
||||
But you don't want to <a href="../../doc/v2/faq.html#question2">
|
||||
to export std::vector<std::string></a>,
|
||||
you want this function to return a python list of strings. <a href="../../index.html">
|
||||
Boost.Python</a> has
|
||||
excellent support for things like that:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>()
|
||||
{
|
||||
</span><span class=identifier>list </span><span class=identifier>result</span><span class=special>;
|
||||
// </span><span class=identifier>call </span><span class=identifier>original </span><span class=identifier>function
|
||||
</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>names</span><span class=special>();
|
||||
// </span><span class=identifier>put </span><span class=identifier>all </span><span class=identifier>the </span><span class=identifier>strings </span><span class=identifier>inside </span><span class=identifier>the </span><span class=identifier>python </span><span class=identifier>list
|
||||
</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>>::</span><span class=identifier>iterator </span><span class=identifier>it</span><span class=special>;
|
||||
</span><span class=keyword>for </span><span class=special>(</span><span class=identifier>it </span><span class=special>= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(); </span><span class=identifier>it </span><span class=special>!= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>end</span><span class=special>(); ++</span><span class=identifier>it</span><span class=special>){
|
||||
</span><span class=identifier>result</span><span class=special>.</span><span class=identifier>append</span><span class=special>(*</span><span class=identifier>it</span><span class=special>);
|
||||
}
|
||||
</span><span class=keyword>return </span><span class=identifier>result</span><span class=special>;
|
||||
}
|
||||
|
||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>test</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"names"</span><span class=special>, &</span><span class=identifier>names_wrapper</span><span class=special>);
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Nice heh? Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt>
|
||||
function in a header named "<tt>test_wrappers.h</tt>" and in the interface file:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Include</span><span class=special>(</span><span class=string>"test_wrappers.h"</span><span class=special>)
|
||||
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=string>"names_wrapper"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
You can optionally declare the function in the interface file itself:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>names_wrapper </span><span class=special>= </span><span class=identifier>Wrapper</span><span class=special>(</span><span class=string>"names_wrapper"</span><span class=special>,
|
||||
</span><span class=string>""</span><span class=string>"
|
||||
list names_wrapper()
|
||||
{
|
||||
// code to call name() and convert the vector to a list...
|
||||
}
|
||||
"</span><span class=string>""</span><span class=special>)
|
||||
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
</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 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>{
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>();
|
||||
}
|
||||
|
||||
</span><span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>* </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
// </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
And then in the interface file:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"C"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>names</span><span class=special>, </span><span class=string>"names_wrapper"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img>Even though <a href="../../index.html">
|
||||
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 member function.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="templates.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,90 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Pyste Documentation</title>
|
||||
<link rel="stylesheet" href="doc/theme/style.css" type="text/css">
|
||||
<link rel="next" href="doc/introduction.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="../../../boost.png">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Pyste Documentation</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="toc_title">Table of contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/introduction.html">Introduction</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/running_pyste.html">Running Pyste</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/the_interface_files.html">The Interface Files</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/renaming_and_excluding.html">Renaming and Excluding</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/policies.html">Policies</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/templates.html">Templates</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/wrappers.html">Wrappers</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/exporting_an_entire_header.html">Exporting An Entire Header</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/smart_pointers.html">Smart Pointers</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/global_variables.html">Global Variables</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/adding_new_methods.html">Adding New Methods</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/inserting_code.html">Inserting Code</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Distributed under
|
||||
the Boost Software License, Version 1.0. (See accompanying file
|
||||
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright Bruno da Silva de Oliveira 2006. Distributed under the Boost
|
||||
# Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Pyste import pyste
|
||||
pyste.main()
|
||||
@@ -1,20 +0,0 @@
|
||||
# Copyright Prabhu Ramachandran 2006. Distributed under the Boost
|
||||
# Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from distutils.core import setup
|
||||
import sys
|
||||
|
||||
setup (name = "Pyste",
|
||||
version = "0.9.10",
|
||||
description = "Pyste - Python Semi-Automatic Exporter",
|
||||
maintainer = "Bruno da Silva de Oliveira",
|
||||
maintainer_email = "nicodemus@globalite.com.br",
|
||||
licence = "Boost License",
|
||||
long_description = "Pyste is a Boost.Python code generator",
|
||||
url = "http://www.boost.org/libs/python/pyste/index.html",
|
||||
platforms = ['Any'],
|
||||
packages = ['Pyste'],
|
||||
scripts = ['pyste.py'],
|
||||
package_dir = {'Pyste': '../src/Pyste'},
|
||||
)
|
||||
@@ -1,918 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import exporters
|
||||
from Exporter import Exporter
|
||||
from declarations import *
|
||||
from settings import *
|
||||
from policies import *
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
from EnumExporter import EnumExporter
|
||||
from utils import makeid, enumerate
|
||||
import copy
|
||||
import exporterutils
|
||||
import re
|
||||
|
||||
#==============================================================================
|
||||
# ClassExporter
|
||||
#==============================================================================
|
||||
class ClassExporter(Exporter):
|
||||
'Generates boost.python code to export a class declaration'
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
# sections of code
|
||||
self.sections = {}
|
||||
# template: each item in the list is an item into the class_<...>
|
||||
# section.
|
||||
self.sections['template'] = []
|
||||
# constructor: each item in the list is a parameter to the class_
|
||||
# constructor, like class_<C>(...)
|
||||
self.sections['constructor'] = []
|
||||
# inside: everything within the class_<> statement
|
||||
self.sections['inside'] = []
|
||||
# scope: items outside the class statement but within its scope.
|
||||
# scope* s = new scope(class<>());
|
||||
# ...
|
||||
# delete s;
|
||||
self.sections['scope'] = []
|
||||
# declarations: outside the BOOST_PYTHON_MODULE macro
|
||||
self.sections['declaration'] = []
|
||||
self.sections['declaration-outside'] = []
|
||||
self.sections['include'] = []
|
||||
# a list of Constructor instances
|
||||
self.constructors = []
|
||||
# a list of code units, generated by nested declarations
|
||||
self.nested_codeunits = []
|
||||
|
||||
|
||||
def ScopeName(self):
|
||||
return makeid(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
if self.declarations:
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.class_ = copy.deepcopy(self.class_)
|
||||
else:
|
||||
self.class_ = None
|
||||
|
||||
|
||||
def ClassBases(self):
|
||||
all_bases = []
|
||||
for level in self.class_.hierarchy:
|
||||
for base in level:
|
||||
all_bases.append(base)
|
||||
return [self.GetDeclaration(x.name) for x in all_bases]
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Return the TOTAL number of bases that this class has, including the
|
||||
bases' bases. Do this because base classes must be instantialized
|
||||
before the derived classes in the module definition.
|
||||
'''
|
||||
num_bases = len(self.ClassBases())
|
||||
return num_bases, self.class_.FullName()
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
self.InheritMethods(exported_names)
|
||||
self.MakeNonVirtual()
|
||||
if not self.info.exclude:
|
||||
self.ExportBasics()
|
||||
self.ExportBases(exported_names)
|
||||
self.ExportConstructors()
|
||||
self.ExportVariables()
|
||||
self.ExportVirtualMethods(codeunit)
|
||||
self.ExportMethods()
|
||||
self.ExportOperators()
|
||||
self.ExportNestedClasses(exported_names)
|
||||
self.ExportNestedEnums(exported_names)
|
||||
self.ExportSmartPointer()
|
||||
self.ExportOpaquePointerPolicies()
|
||||
self.ExportAddedCode()
|
||||
self.Write(codeunit)
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def InheritMethods(self, exported_names):
|
||||
'''Go up in the class hierarchy looking for classes that were not
|
||||
exported yet, and then add their public members to this classes
|
||||
members, as if they were members of this class. This allows the user to
|
||||
just export one type and automatically get all the members from the
|
||||
base classes.
|
||||
'''
|
||||
valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration)
|
||||
fullnames = [x.FullName() for x in self.class_]
|
||||
pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)]
|
||||
fullnames = dict([(x, None) for x in fullnames])
|
||||
pointers = dict([(x, None) for x in pointers])
|
||||
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:
|
||||
if type(member) in valid_members:
|
||||
member_copy = copy.deepcopy(member)
|
||||
member_copy.class_ = self.class_.FullName()
|
||||
if isinstance(member_copy, Method):
|
||||
pointer = member_copy.PointerDeclaration(True)
|
||||
if pointer not in pointers:
|
||||
self.class_.AddMember(member)
|
||||
pointers[pointer] = None
|
||||
elif member_copy.FullName() not in fullnames:
|
||||
self.class_.AddMember(member)
|
||||
else:
|
||||
level_exported = True
|
||||
if level_exported:
|
||||
break
|
||||
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 Write(self, codeunit):
|
||||
indent = self.INDENT
|
||||
boost_ns = namespaces.python
|
||||
pyste_ns = namespaces.pyste
|
||||
code = ''
|
||||
# begin a scope for this class if needed
|
||||
nested_codeunits = self.nested_codeunits
|
||||
needs_scope = self.sections['scope'] or nested_codeunits
|
||||
if needs_scope:
|
||||
scope_name = self.ScopeName()
|
||||
code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\
|
||||
(scope_name, boost_ns)
|
||||
# export the template section
|
||||
template_params = ', '.join(self.sections['template'])
|
||||
code += indent + boost_ns + 'class_< %s >' % template_params
|
||||
# export the constructor section
|
||||
constructor_params = ', '.join(self.sections['constructor'])
|
||||
code += '(%s)\n' % constructor_params
|
||||
# export the inside section
|
||||
in_indent = indent*2
|
||||
for line in self.sections['inside']:
|
||||
code += in_indent + line + '\n'
|
||||
# write the scope section and end it
|
||||
if not needs_scope:
|
||||
code += indent + ';\n'
|
||||
else:
|
||||
code += indent + ');\n'
|
||||
for line in self.sections['scope']:
|
||||
code += indent + line + '\n'
|
||||
# write the contents of the nested classes
|
||||
for nested_unit in nested_codeunits:
|
||||
code += '\n' + nested_unit.Section('module')
|
||||
# close the scope
|
||||
code += indent + 'delete %s;\n' % scope_name
|
||||
|
||||
# write the code to the module section in the codeunit
|
||||
codeunit.Write('module', code + '\n')
|
||||
|
||||
# write the declarations to the codeunit
|
||||
declarations = '\n'.join(self.sections['declaration'])
|
||||
for nested_unit in nested_codeunits:
|
||||
declarations += nested_unit.Section('declaration')
|
||||
if declarations:
|
||||
codeunit.Write('declaration', declarations + '\n')
|
||||
declarations_outside = '\n'.join(self.sections['declaration-outside'])
|
||||
if declarations_outside:
|
||||
codeunit.Write('declaration-outside', declarations_outside + '\n')
|
||||
|
||||
# write the includes to the codeunit
|
||||
includes = '\n'.join(self.sections['include'])
|
||||
for nested_unit in nested_codeunits:
|
||||
includes += nested_unit.Section('include')
|
||||
if includes:
|
||||
codeunit.Write('include', includes)
|
||||
|
||||
|
||||
def Add(self, section, item):
|
||||
'Add the item into the corresponding section'
|
||||
self.sections[section].append(item)
|
||||
|
||||
|
||||
def ExportBasics(self):
|
||||
'''Export the name of the class and its class_ statement.'''
|
||||
class_name = self.class_.FullName()
|
||||
self.Add('template', class_name)
|
||||
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
|
||||
exported = []
|
||||
for level in hierarchy:
|
||||
for base in level:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
exported.append(base.name)
|
||||
if exported:
|
||||
break
|
||||
if exported:
|
||||
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
|
||||
self.Add('template', code)
|
||||
|
||||
|
||||
def ExportConstructors(self):
|
||||
'''Exports all the public contructors of the class, plus indicates if the
|
||||
class is noncopyable.
|
||||
'''
|
||||
py_ns = namespaces.python
|
||||
indent = self.INDENT
|
||||
|
||||
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:]
|
||||
min_params = ', '.join(min_params_list)
|
||||
max_params = ', '.join(max_params_list)
|
||||
init = py_ns + 'init< '
|
||||
init += min_params
|
||||
if max_params:
|
||||
if min_params:
|
||||
init += ', '
|
||||
init += py_ns + ('optional< %s >' % max_params)
|
||||
init += ' >()'
|
||||
return init
|
||||
|
||||
constructors = [x for x in self.public_members if isinstance(x, Constructor)]
|
||||
# don't export copy constructors if the class is abstract
|
||||
# we could remove all constructors, but this will have the effect of
|
||||
# inserting no_init in the declaration, which would not allow
|
||||
# even subclasses to be instantiated.
|
||||
self.constructors = constructors[:]
|
||||
if self.class_.abstract:
|
||||
for cons in constructors:
|
||||
if cons.IsCopy():
|
||||
constructors.remove(cons)
|
||||
break
|
||||
|
||||
if not constructors:
|
||||
# declare no_init
|
||||
self.Add('constructor', py_ns + 'no_init')
|
||||
else:
|
||||
# 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):
|
||||
smaller = cons
|
||||
assert smaller is not None
|
||||
self.Add('constructor', init_code(smaller))
|
||||
constructors.remove(smaller)
|
||||
# write the rest to the inside section, using def()
|
||||
for cons in constructors:
|
||||
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:
|
||||
self.Add('template', namespaces.boost + 'noncopyable')
|
||||
|
||||
|
||||
def ExportVariables(self):
|
||||
'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:
|
||||
continue
|
||||
name = self.info[var.name].rename or var.name
|
||||
fullname = var.FullName()
|
||||
if var.type.const:
|
||||
def_ = '.def_readonly'
|
||||
else:
|
||||
def_ = '.def_readwrite'
|
||||
code = '%s("%s", &%s)' % (def_, name, fullname)
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
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)
|
||||
return name + overloads
|
||||
|
||||
|
||||
def GetAddedMethods(self):
|
||||
added_methods = self.info.__added__
|
||||
result = []
|
||||
if added_methods:
|
||||
for name, rename in added_methods:
|
||||
decl = self.GetDeclaration(name)
|
||||
self.info[name].rename = rename
|
||||
result.append(decl)
|
||||
return result
|
||||
|
||||
|
||||
def ExportMethods(self):
|
||||
'''Export all the non-virtual methods of this class, plus any function
|
||||
that is to be exported as a method'''
|
||||
|
||||
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()
|
||||
macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS'
|
||||
else:
|
||||
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)
|
||||
if code not in declared:
|
||||
declared[code] = True
|
||||
self.Add('declaration', code)
|
||||
|
||||
|
||||
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[m.name].wrapper
|
||||
if wrapper:
|
||||
return '&' + wrapper.FullName()
|
||||
else:
|
||||
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
|
||||
|
||||
methods = [x for x in self.public_members if IsExportable(x)]
|
||||
methods.extend(self.GetAddedMethods())
|
||||
|
||||
staticmethods = {}
|
||||
|
||||
for method in methods:
|
||||
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
|
||||
|
||||
# warn the user if this method needs a policy and doesn't have one
|
||||
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
|
||||
|
||||
# check for policies
|
||||
policy = method_info.policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
# check for overloads
|
||||
overload = ''
|
||||
if method.minArgs != method.maxArgs and not method_info.wrapper:
|
||||
# add the overloads for this method
|
||||
DeclareOverloads(method)
|
||||
overload_name = self.OverloadName(method)
|
||||
overload = ', %s%s()' % (namespaces.pyste, overload_name)
|
||||
|
||||
# build the .def string to export the method
|
||||
pointer = Pointer(method)
|
||||
code = '.def("%s", %s' % (name, pointer)
|
||||
code += policy
|
||||
code += overload
|
||||
code += ')'
|
||||
self.Add('inside', code)
|
||||
# static method
|
||||
if isinstance(method, Method) and method.static:
|
||||
staticmethods[name] = 1
|
||||
# add wrapper code if this method has one
|
||||
wrapper = method_info.wrapper
|
||||
if wrapper and wrapper.code:
|
||||
self.Add('declaration', wrapper.code)
|
||||
|
||||
# export staticmethod statements
|
||||
for name in staticmethods:
|
||||
code = '.staticmethod("%s")' % name
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
|
||||
def MakeNonVirtual(self):
|
||||
'''Make all methods that the user indicated to no_override no more virtual, delegating their
|
||||
export to the ExportMethods routine'''
|
||||
for member in self.class_:
|
||||
if type(member) == Method and member.virtual:
|
||||
member.virtual = not self.info[member.name].no_override
|
||||
|
||||
|
||||
def ExportVirtualMethods(self, codeunit):
|
||||
# check if this class has any virtual methods
|
||||
has_virtual_methods = False
|
||||
for member in self.class_:
|
||||
if type(member) == Method and member.virtual:
|
||||
has_virtual_methods = True
|
||||
break
|
||||
|
||||
holder = self.info.holder
|
||||
if has_virtual_methods:
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info, codeunit)
|
||||
if holder:
|
||||
self.Add('template', holder(generator.FullName()))
|
||||
else:
|
||||
self.Add('template', generator.FullName())
|
||||
for definition in generator.GenerateDefinitions():
|
||||
self.Add('inside', definition)
|
||||
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
|
||||
else:
|
||||
if holder:
|
||||
self.Add('template', holder(self.class_.FullName()))
|
||||
|
||||
# operators natively supported by boost
|
||||
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -= '\
|
||||
'*= /= %= ^= &= |= <<= >>='.split()
|
||||
# create a map for faster lookup
|
||||
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 name
|
||||
BOOST_RENAME_OPERATORS = {
|
||||
'()' : '__call__',
|
||||
}
|
||||
|
||||
# converters which have a special name in python
|
||||
# it's a map of a regular expression of the converter's result to the
|
||||
# appropriate python name
|
||||
SPECIAL_CONVERTERS = {
|
||||
re.compile(r'(const)?\s*double$') : '__float__',
|
||||
re.compile(r'(const)?\s*float$') : '__float__',
|
||||
re.compile(r'(const)?\s*int$') : '__int__',
|
||||
re.compile(r'(const)?\s*long$') : '__long__',
|
||||
re.compile(r'(const)?\s*char\s*\*?$') : '__str__',
|
||||
re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__',
|
||||
}
|
||||
|
||||
|
||||
def ExportOperators(self):
|
||||
'Export all member operators and free operators related to this class'
|
||||
|
||||
def GetFreeOperators():
|
||||
'Get all the free (global) operators related to this class'
|
||||
operators = []
|
||||
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():
|
||||
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():
|
||||
return namespaces.python + 'self'
|
||||
else:
|
||||
return namespaces.python + ('other< %s >()' % param.name)
|
||||
|
||||
|
||||
def HandleSpecialOperator(operator):
|
||||
# gatter information about the operator and its parameters
|
||||
result_name = operator.result.name
|
||||
param1_name = ''
|
||||
if operator.parameters:
|
||||
param1_name = operator.parameters[0].name
|
||||
|
||||
# check for str
|
||||
ostream = 'basic_ostream'
|
||||
is_str = result_name.find(ostream) != -1 and param1_name.find(ostream) != -1
|
||||
if is_str:
|
||||
namespace = namespaces.python + 'self_ns::'
|
||||
self_ = namespaces.python + 'self'
|
||||
return '.def(%sstr(%s))' % (namespace, self_)
|
||||
|
||||
# is not a special operator
|
||||
return None
|
||||
|
||||
|
||||
|
||||
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]
|
||||
|
||||
for operator in operators:
|
||||
# gatter information about the operator, for use later
|
||||
wrapper = self.info['operator'][operator.name].wrapper
|
||||
if wrapper:
|
||||
pointer = '&' + wrapper.FullName()
|
||||
if wrapper.code:
|
||||
self.Add('declaration-outside', wrapper.code)
|
||||
else:
|
||||
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
|
||||
|
||||
# check if this operator has a special representation in boost
|
||||
special_code = HandleSpecialOperator(operator)
|
||||
has_special_representation = special_code is not None
|
||||
|
||||
if export_as_method:
|
||||
# export this operator as a normal method, renaming or using the given wrapper
|
||||
if not rename:
|
||||
if wrapper:
|
||||
rename = wrapper.name
|
||||
else:
|
||||
rename = self.BOOST_RENAME_OPERATORS[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))
|
||||
|
||||
elif has_special_representation:
|
||||
self.Add('inside', special_code)
|
||||
|
||||
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
|
||||
if is_unary:
|
||||
self.Add('inside', '.def( %s%sself )' % \
|
||||
(operator.name, namespaces.python))
|
||||
else:
|
||||
# binary operator
|
||||
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])
|
||||
self.Add('inside', '.def( %s %s %s )' % \
|
||||
(left_operand, operator.name, right_operand))
|
||||
|
||||
# export the converters.
|
||||
# export them as simple functions with a pre-determined name
|
||||
|
||||
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
|
||||
for regex, method_name in self.SPECIAL_CONVERTERS.items():
|
||||
if regex.match(result_fullname):
|
||||
return method_name
|
||||
else:
|
||||
# extract the last name from the full name
|
||||
result_name = makeid(result_name)
|
||||
return 'to_' + result_name
|
||||
|
||||
for converter in converters:
|
||||
info = self.info['operator'][converter.result.FullName()]
|
||||
# check if this operator should be excluded
|
||||
if info.exclude:
|
||||
continue
|
||||
|
||||
special_code = HandleSpecialOperator(converter)
|
||||
if info.rename or not special_code:
|
||||
# export as method
|
||||
name = info.rename or ConverterMethodName(converter)
|
||||
pointer = converter.PointerDeclaration()
|
||||
policy_code = ''
|
||||
if info.policy:
|
||||
policy_code = ', %s()' % info.policy.Code()
|
||||
self.Add('inside', '.def("%s", %s%s)' % (name, pointer, policy_code))
|
||||
|
||||
elif special_code:
|
||||
self.Add('inside', special_code)
|
||||
|
||||
|
||||
|
||||
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.include = self.info.include
|
||||
nested_info.name = nested_class.FullName()
|
||||
exporter = self.__class__(nested_info)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
def ExportNestedEnums(self, exported_names):
|
||||
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.include = self.info.include
|
||||
enum_info.name = enum.FullName()
|
||||
exporter = EnumExporter(enum_info)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
def ExportSmartPointer(self):
|
||||
smart_ptr = self.info.smart_ptr
|
||||
if smart_ptr:
|
||||
class_name = self.class_.FullName()
|
||||
smart_ptr = smart_ptr % class_name
|
||||
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
|
||||
|
||||
|
||||
def ExportOpaquePointerPolicies(self):
|
||||
# check all methods for 'return_opaque_pointer' policies
|
||||
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 = exporterutils.EspecializeTypeID(method.result.name)
|
||||
if macro:
|
||||
self.Add('declaration-outside', macro)
|
||||
|
||||
def ExportAddedCode(self):
|
||||
if self.info.__code__:
|
||||
for code in self.info.__code__:
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Virtual Wrapper utils
|
||||
#==============================================================================
|
||||
|
||||
def _ParamsInfo(m, count=None):
|
||||
if count is None:
|
||||
count = len(m.parameters)
|
||||
param_names = ['p%i' % i for i in range(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:
|
||||
# #params[i] += '=%s' % p.default
|
||||
# params[i] += '=%s' % (p.name + '()')
|
||||
params = ', '.join(params)
|
||||
return params, param_names, param_types
|
||||
|
||||
|
||||
class _VirtualWrapperGenerator(object):
|
||||
'Generates code to export the virtual methods of the given class'
|
||||
|
||||
def __init__(self, class_, bases, info, codeunit):
|
||||
self.class_ = copy.deepcopy(class_)
|
||||
self.bases = bases[:]
|
||||
self.info = info
|
||||
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
|
||||
self.virtual_methods = None
|
||||
self._method_count = {}
|
||||
self.codeunit = codeunit
|
||||
self.GenerateVirtualMethods()
|
||||
|
||||
|
||||
SELF = 'py_self'
|
||||
|
||||
|
||||
def DefaultImplementationNames(self, method):
|
||||
'''Returns a list of default implementations for this method, one for each
|
||||
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
|
||||
if minArgs == maxArgs:
|
||||
return [base_name]
|
||||
else:
|
||||
return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)]
|
||||
|
||||
|
||||
def Declaration(self, method, indent):
|
||||
'''Returns a string with the declarations of the virtual wrapper and
|
||||
its default implementations. This string must be put inside the Wrapper
|
||||
body.
|
||||
'''
|
||||
pyste = namespaces.pyste
|
||||
python = namespaces.python
|
||||
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:
|
||||
constantness = ' const'
|
||||
|
||||
# call_method callback
|
||||
decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions())
|
||||
param_names_str = ', '.join(param_names)
|
||||
if param_names_str:
|
||||
param_names_str = ', ' + param_names_str
|
||||
|
||||
self_str = self.SELF
|
||||
|
||||
decl += indent*2 + '%(return_str)s%(python)scall_method< %(result)s >' \
|
||||
'(%(self_str)s, "%(rename)s"%(param_names_str)s);\n' % locals()
|
||||
decl += indent + '}\n'
|
||||
|
||||
# default implementations (with overloading)
|
||||
def DefaultImpl(method, param_names):
|
||||
'Return the body of a default implementation wrapper'
|
||||
indent2 = indent * 2
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if not wrapper:
|
||||
# return the default implementation of the class
|
||||
return indent2 + '%s%s(%s);\n' % \
|
||||
(return_str, method.FullName(), ', '.join(param_names))
|
||||
else:
|
||||
if wrapper.code:
|
||||
self.codeunit.Write('declaration-outside', wrapper.code)
|
||||
# return a call for the wrapper
|
||||
params = ', '.join(['this'] + param_names)
|
||||
return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
|
||||
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)
|
||||
decl += '\n'
|
||||
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
|
||||
decl += DefaultImpl(method, param_names)
|
||||
decl += indent + '}\n'
|
||||
return decl
|
||||
|
||||
|
||||
def MethodDefinition(self, method):
|
||||
'''Returns a list of lines, which should be put inside the class_
|
||||
statement to export this method.'''
|
||||
# dont define abstract methods
|
||||
pyste = namespaces.pyste
|
||||
rename = self.info[method.name].rename or method.name
|
||||
default_names = self.DefaultImplementationNames(method)
|
||||
class_name = self.class_.FullName()
|
||||
wrapper_name = pyste + self.wrapper_name
|
||||
result = method.result.FullName()
|
||||
is_method_unique = method.is_unique
|
||||
constantness = ''
|
||||
if method.const:
|
||||
constantness = ' const'
|
||||
|
||||
# create a list of default-impl pointers
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
if method.abstract:
|
||||
default_pointers = []
|
||||
elif 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]]
|
||||
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
|
||||
pointer = method.PointerDeclaration()
|
||||
if method.abstract:
|
||||
pointer = namespaces.python + ('pure_virtual(%s)' % pointer)
|
||||
|
||||
# warn the user if this method needs a policy and doesn't have one
|
||||
method_info = self.info[method.name]
|
||||
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
|
||||
|
||||
# Add policy to overloaded methods also
|
||||
policy = method_info.policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
|
||||
# generate the defs
|
||||
definitions = []
|
||||
# basic def
|
||||
if default_pointers:
|
||||
definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy))
|
||||
for default_pointer in default_pointers[:-1]:
|
||||
definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy))
|
||||
else:
|
||||
definitions.append('.def("%s", %s%s)' % (rename, pointer, policy))
|
||||
return definitions
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return namespaces.pyste + self.wrapper_name
|
||||
|
||||
|
||||
def GenerateVirtualMethods(self):
|
||||
'''To correctly export all virtual methods, we must also make wrappers
|
||||
for the virtual methods of the bases of this class, as if the methods
|
||||
were from this class itself.
|
||||
This method creates the instance variable self.virtual_methods.
|
||||
'''
|
||||
def IsVirtual(m):
|
||||
if type(m) is Method:
|
||||
pure_virtual = m.abstract and m.virtual
|
||||
virtual = m.virtual and m.visibility != Scope.private
|
||||
return virtual or pure_virtual
|
||||
else:
|
||||
return False
|
||||
|
||||
# extract the virtual methods, avoiding duplications. The duplication
|
||||
# must take in account the full signature without the class name, so
|
||||
# that inherited members are correctly excluded if the subclass overrides
|
||||
# them.
|
||||
def MethodSig(method):
|
||||
if method.const:
|
||||
const = ' const'
|
||||
else:
|
||||
const = ''
|
||||
if method.result:
|
||||
result = method.result.FullName()
|
||||
else:
|
||||
result = ''
|
||||
params = ', '.join([x.FullName() for x in method.parameters])
|
||||
return '%s %s(%s)%s%s' % (
|
||||
result, method.name, params, const, method.Exceptions())
|
||||
|
||||
already_added = {}
|
||||
self.virtual_methods = []
|
||||
for member in self.class_:
|
||||
if IsVirtual(member):
|
||||
already_added[MethodSig(member)] = None
|
||||
self.virtual_methods.append(member)
|
||||
|
||||
for base in self.bases:
|
||||
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
|
||||
for base_method in base_methods:
|
||||
self.class_.AddMember(base_method)
|
||||
|
||||
all_methods = [x for x in self.class_ if IsVirtual(x)]
|
||||
|
||||
for member in all_methods:
|
||||
sig = MethodSig(member)
|
||||
if IsVirtual(member) and not sig in already_added:
|
||||
self.virtual_methods.append(member)
|
||||
already_added[sig] = 0
|
||||
|
||||
|
||||
def Constructors(self):
|
||||
return self.class_.Constructors(publics_only=True)
|
||||
|
||||
|
||||
def GenerateDefinitions(self):
|
||||
defs = []
|
||||
for method in self.virtual_methods:
|
||||
exclude = self.info[method.name].exclude
|
||||
# generate definitions only for public methods and non-abstract methods
|
||||
if method.visibility == Scope.public and not exclude:
|
||||
defs.extend(self.MethodDefinition(method))
|
||||
return defs
|
||||
|
||||
|
||||
def GenerateVirtualWrapper(self, indent):
|
||||
'Return the wrapper for this class'
|
||||
|
||||
# generate the class code
|
||||
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
|
||||
# from the min number of arguments to the max number, generate
|
||||
# all version of the given constructor
|
||||
cons_code = ''
|
||||
for argNum in range(minArgs, maxArgs+1):
|
||||
params, param_names, param_types = _ParamsInfo(cons, argNum)
|
||||
if params:
|
||||
params = ', ' + params
|
||||
cons_code += indent + '%s(PyObject* %s_%s):\n' % \
|
||||
(self.wrapper_name, self.SELF, params)
|
||||
cons_code += indent*2 + '%s(%s), %s(%s_) {}\n\n' % \
|
||||
(class_name, ', '.join(param_names), self.SELF, self.SELF)
|
||||
code += cons_code
|
||||
# generate the body
|
||||
body = []
|
||||
for method in self.virtual_methods:
|
||||
if not self.info[method.name].exclude:
|
||||
body.append(self.Declaration(method, indent))
|
||||
body = '\n'.join(body)
|
||||
code += body + '\n'
|
||||
# add the self member
|
||||
code += indent + 'PyObject* %s;\n' % self.SELF
|
||||
code += '};\n'
|
||||
return code
|
||||
@@ -1,26 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Exporter import Exporter
|
||||
|
||||
#==============================================================================
|
||||
# CodeExporter
|
||||
#==============================================================================
|
||||
class CodeExporter(Exporter):
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.code
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
codeunit.Write(self.info.section, self.info.code)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
pass
|
||||
@@ -1,247 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from GCCXMLParser import ParseDeclarations
|
||||
import tempfile
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
import settings
|
||||
import shutil
|
||||
import shelve
|
||||
from cPickle import dump, load
|
||||
|
||||
#==============================================================================
|
||||
# exceptions
|
||||
#==============================================================================
|
||||
class CppParserError(Exception): pass
|
||||
|
||||
#==============================================================================
|
||||
# CppParser
|
||||
#==============================================================================
|
||||
class CppParser:
|
||||
'Parses a header file and returns a list of declarations'
|
||||
|
||||
def __init__(self, includes=None, defines=None, cache_dir=None, version=None, gccxml_path = 'gccxml'):
|
||||
'includes and defines ar the directives given to gcc'
|
||||
if includes is None:
|
||||
includes = []
|
||||
if defines is None:
|
||||
defines = []
|
||||
self.includes = includes
|
||||
self.gccxml_path = gccxml_path
|
||||
self.defines = defines
|
||||
self.version = version
|
||||
#if cache_dir is None:
|
||||
# cache_dir = tempfile.mktemp()
|
||||
# self.delete_cache = True
|
||||
#else:
|
||||
# self.delete_cache = False
|
||||
self.delete_cache = False
|
||||
self.cache_dir = cache_dir
|
||||
self.cache_files = []
|
||||
self.mem_cache = {}
|
||||
# create the cache dir
|
||||
if cache_dir:
|
||||
try:
|
||||
os.makedirs(cache_dir)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self.Close()
|
||||
|
||||
|
||||
def _IncludeParams(self, filename):
|
||||
includes = self.includes[:]
|
||||
filedir = os.path.dirname(filename)
|
||||
if not filedir:
|
||||
filedir = '.'
|
||||
includes.insert(0, filedir)
|
||||
includes = ['-I "%s"' % self.Unixfy(x) for x in includes]
|
||||
return ' '.join(includes)
|
||||
|
||||
|
||||
def _DefineParams(self):
|
||||
defines = ['-D "%s"' % x for x in self.defines]
|
||||
return ' '.join(defines)
|
||||
|
||||
|
||||
def FindHeader(self, header):
|
||||
if os.path.isfile(header):
|
||||
return header
|
||||
for path in self.includes:
|
||||
filename = os.path.join(path, header)
|
||||
if os.path.isfile(filename):
|
||||
return filename
|
||||
else:
|
||||
name = os.path.basename(header)
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
|
||||
|
||||
def AppendTail(self, filename, tail):
|
||||
'''Creates a temporary file, appends the text tail to it, and returns
|
||||
the filename of the file.
|
||||
'''
|
||||
if hasattr(tempfile, 'mkstemp'):
|
||||
f_no, temp = tempfile.mkstemp('.h')
|
||||
f = file(temp, 'a')
|
||||
os.close(f_no)
|
||||
else:
|
||||
temp = tempfile.mktemp('.h')
|
||||
f = file(temp, 'a')
|
||||
f.write('#include "%s"\n\n' % os.path.abspath(filename))
|
||||
f.write(tail)
|
||||
f.write('\n')
|
||||
f.close()
|
||||
return temp
|
||||
|
||||
|
||||
def Unixfy(self, path):
|
||||
return path.replace('\\', '/')
|
||||
|
||||
|
||||
def ParseWithGCCXML(self, header, tail):
|
||||
'''Parses the given header using gccxml and GCCXMLParser.
|
||||
'''
|
||||
header = self.FindHeader(header)
|
||||
if tail:
|
||||
filename = self.AppendTail(header, tail)
|
||||
else:
|
||||
filename = header
|
||||
xmlfile = tempfile.mktemp('.xml')
|
||||
try:
|
||||
# get the params
|
||||
includes = self._IncludeParams(filename)
|
||||
defines = self._DefineParams()
|
||||
# call gccxml
|
||||
cmd = '%s %s %s "%s" -fxml=%s'
|
||||
filename = self.Unixfy(filename)
|
||||
xmlfile = self.Unixfy(xmlfile)
|
||||
status = os.system(cmd % (self.gccxml_path, includes, defines, filename, xmlfile))
|
||||
if status != 0 or not os.path.isfile(xmlfile):
|
||||
raise CppParserError, 'Error executing gccxml'
|
||||
# parse the resulting xml
|
||||
declarations = ParseDeclarations(xmlfile)
|
||||
# make the declarations' location to point to the original file
|
||||
if tail:
|
||||
for decl in declarations:
|
||||
decl_filename = os.path.normpath(os.path.normcase(decl.location[0]))
|
||||
filename = os.path.normpath(os.path.normcase(filename))
|
||||
if decl_filename == filename:
|
||||
decl.location = header, decl.location[1]
|
||||
# return the declarations
|
||||
return declarations
|
||||
finally:
|
||||
if settings.DEBUG and os.path.isfile(xmlfile):
|
||||
debugname = os.path.basename(header)
|
||||
debugname = os.path.splitext(debugname)[0] + '.xml'
|
||||
print 'DEBUG:', debugname
|
||||
shutil.copy(xmlfile, debugname)
|
||||
# delete the temporary files
|
||||
try:
|
||||
os.remove(xmlfile)
|
||||
if tail:
|
||||
os.remove(filename)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def Parse(self, header, interface, tail=None):
|
||||
'''Parses the given filename related to the given interface and returns
|
||||
the (declarations, headerfile). The header returned is normally the
|
||||
same as the given to this method (except that it is the full path),
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to
|
||||
gccxml. This temp filename is then returned.
|
||||
'''
|
||||
if tail is None:
|
||||
tail = ''
|
||||
tail = tail.strip()
|
||||
declarations = self.GetCache(header, interface, tail)
|
||||
if declarations is None:
|
||||
declarations = self.ParseWithGCCXML(header, tail)
|
||||
self.CreateCache(header, interface, tail, declarations)
|
||||
header_fullpath = os.path.abspath(self.FindHeader(header))
|
||||
return declarations, header_fullpath
|
||||
|
||||
|
||||
def CacheFileName(self, interface):
|
||||
interface_name = os.path.basename(interface)
|
||||
cache_file = os.path.splitext(interface_name)[0] + '.pystec'
|
||||
cache_file = os.path.join(self.cache_dir, cache_file)
|
||||
return cache_file
|
||||
|
||||
|
||||
def GetCache(self, header, interface, tail):
|
||||
key = (header, interface, tail)
|
||||
# try memory cache first
|
||||
if key in self.mem_cache:
|
||||
return self.mem_cache[key]
|
||||
|
||||
# get the cache from the disk
|
||||
if self.cache_dir is None:
|
||||
return None
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
version = load(f)
|
||||
if version != self.version:
|
||||
return None
|
||||
cache = load(f)
|
||||
if cache.has_key(key):
|
||||
self.cache_files.append(cache_file)
|
||||
return cache[key]
|
||||
else:
|
||||
return None
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def CreateCache(self, header, interface, tail, declarations):
|
||||
key = (header, interface, tail)
|
||||
|
||||
# our memory cache only holds one item
|
||||
self.mem_cache.clear()
|
||||
self.mem_cache[key] = declarations
|
||||
|
||||
# save the cache in the disk
|
||||
if self.cache_dir is None:
|
||||
return
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
version = load(f)
|
||||
cache = load(f)
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
cache = {}
|
||||
cache[key] = declarations
|
||||
self.cache_files.append(cache_file)
|
||||
f = file(cache_file, 'wb')
|
||||
try:
|
||||
dump(self.version, f, 1)
|
||||
dump(cache, f, 1)
|
||||
finally:
|
||||
f.close()
|
||||
return cache_file
|
||||
|
||||
|
||||
def Close(self):
|
||||
if self.delete_cache and self.cache_files:
|
||||
for filename in self.cache_files:
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
self.cache_files = []
|
||||
shutil.rmtree(self.cache_dir)
|
||||
@@ -1,58 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Exporter import Exporter
|
||||
from settings import *
|
||||
import utils
|
||||
|
||||
#==============================================================================
|
||||
# EnumExporter
|
||||
#==============================================================================
|
||||
class EnumExporter(Exporter):
|
||||
'Exports enumerators'
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
if self.declarations:
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
else:
|
||||
self.enum = None
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
if self.info.exclude:
|
||||
return
|
||||
indent = self.INDENT
|
||||
in_indent = self.INDENT*2
|
||||
rename = self.info.rename or self.enum.name
|
||||
full_name = self.enum.FullName()
|
||||
unnamed_enum = False
|
||||
if rename.startswith('$_') or rename.startswith('._'):
|
||||
unnamed_enum = True
|
||||
code = ''
|
||||
if not unnamed_enum:
|
||||
code += indent + namespaces.python
|
||||
code += 'enum_< %s >("%s")\n' % (full_name, rename)
|
||||
for name in self.enum.values:
|
||||
rename = self.info[name].rename or name
|
||||
value_fullname = self.enum.ValueFullName(name)
|
||||
if not unnamed_enum:
|
||||
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
|
||||
else:
|
||||
code += indent + namespaces.python
|
||||
code += 'scope().attr("%s") = (int)%s;\n' % (rename, value_fullname )
|
||||
if self.info.export_values and not unnamed_enum:
|
||||
code += in_indent + '.export_values()\n'
|
||||
if not unnamed_enum:
|
||||
code += indent + ';\n'
|
||||
code += '\n'
|
||||
codeunit.Write('module', code)
|
||||
exported_names[self.enum.FullName()] = 1
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
@@ -1,94 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os.path
|
||||
|
||||
#==============================================================================
|
||||
# Exporter
|
||||
#==============================================================================
|
||||
class Exporter(object):
|
||||
'Base class for objects capable to generate boost.python code.'
|
||||
|
||||
INDENT = ' ' * 4
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
self.info = info
|
||||
self.parser_tail = parser_tail
|
||||
self.interface_file = None
|
||||
self.declarations = []
|
||||
|
||||
|
||||
def Name(self):
|
||||
raise NotImplementedError(self.__class__.__name__)
|
||||
|
||||
|
||||
def Tail(self):
|
||||
return self.parser_tail
|
||||
|
||||
|
||||
def Parse(self, parser):
|
||||
self.parser = parser
|
||||
header = self.info.include
|
||||
tail = self.parser_tail
|
||||
declarations, parser_header = parser.parse(header, tail)
|
||||
self.parser_header = parser_header
|
||||
self.SetDeclarations(declarations)
|
||||
|
||||
|
||||
def SetParsedHeader(self, parsed_header):
|
||||
self.parser_header = parsed_header
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
self.declarations = declarations
|
||||
|
||||
|
||||
def GenerateCode(self, codeunit, exported_names):
|
||||
self.WriteInclude(codeunit)
|
||||
self.Export(codeunit, exported_names)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
codeunit.Write('include', '#include <%s>\n' % self.info.include)
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
'subclasses must override this to do the real work'
|
||||
pass
|
||||
|
||||
|
||||
def GetDeclarations(self, fullname):
|
||||
decls = []
|
||||
for decl in self.declarations:
|
||||
if decl.FullName() == fullname:
|
||||
decls.append(decl)
|
||||
if not decls:
|
||||
raise RuntimeError, 'no %s declaration found!' % fullname
|
||||
return decls
|
||||
|
||||
|
||||
def GetDeclaration(self, fullname):
|
||||
decls = self.GetDeclarations(fullname)
|
||||
#assert len(decls) == 1
|
||||
return decls[0]
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Returns a string that uniquely identifies this instance. All
|
||||
exporters will be sorted by Order before being exported.
|
||||
'''
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Header(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return type(self) is type(other) and self.Name() == other.Name() \
|
||||
and self.interface_file == other.interface_file
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
@@ -1,92 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Exporter import Exporter
|
||||
from policies import *
|
||||
from declarations import *
|
||||
from settings import *
|
||||
import utils
|
||||
import exporterutils
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionExporter
|
||||
#==============================================================================
|
||||
class FunctionExporter(Exporter):
|
||||
'Generates boost.python code to export the given function.'
|
||||
|
||||
def __init__(self, info, tail=None):
|
||||
Exporter.__init__(self, info, tail)
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
if not self.info.exclude:
|
||||
decls = self.GetDeclarations(self.info.name)
|
||||
for decl in decls:
|
||||
self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
|
||||
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
|
||||
self.ExportOpaquePointer(decl, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def ExportDeclaration(self, decl, unique, codeunit):
|
||||
name = self.info.rename or decl.name
|
||||
defs = namespaces.python + 'def("%s", ' % name
|
||||
wrapper = self.info.wrapper
|
||||
if wrapper:
|
||||
pointer = '&' + wrapper.FullName()
|
||||
else:
|
||||
pointer = decl.PointerDeclaration()
|
||||
defs += pointer
|
||||
defs += self.PolicyCode()
|
||||
overload = self.OverloadName(decl)
|
||||
if overload:
|
||||
defs += ', %s()' % (namespaces.pyste + overload)
|
||||
defs += ');'
|
||||
codeunit.Write('module', self.INDENT + defs + '\n')
|
||||
# add the code of the wrapper
|
||||
if wrapper and wrapper.code:
|
||||
codeunit.Write('declaration', wrapper.code + '\n')
|
||||
|
||||
|
||||
def OverloadName(self, decl):
|
||||
if decl.minArgs != decl.maxArgs:
|
||||
return '%s_overloads_%i_%i' % \
|
||||
(decl.name, decl.minArgs, decl.maxArgs)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def GenerateOverloads(self, declarations, codeunit):
|
||||
codes = {}
|
||||
for decl in declarations:
|
||||
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)
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
codes[overload] = None
|
||||
|
||||
|
||||
def PolicyCode(self):
|
||||
policy = self.info.policy
|
||||
if policy is not None:
|
||||
assert isinstance(policy, Policy)
|
||||
return ', %s()' % policy.Code()
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def ExportOpaquePointer(self, function, codeunit):
|
||||
if self.info.policy == return_value_policy(return_opaque_pointer):
|
||||
typename = function.result.name
|
||||
macro = exporterutils.EspecializeTypeID(typename)
|
||||
if macro:
|
||||
codeunit.Write('declaration-outside', macro)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
@@ -1,478 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from declarations import *
|
||||
try:
|
||||
# try to use internal elementtree
|
||||
from xml.etree.cElementTree import ElementTree
|
||||
except ImportError:
|
||||
# try to use cElementTree if avaiable
|
||||
try:
|
||||
from cElementTree import ElementTree
|
||||
except ImportError:
|
||||
# fall back to the normal elementtree
|
||||
from elementtree.ElementTree import ElementTree
|
||||
from xml.parsers.expat import ExpatError
|
||||
from copy import deepcopy
|
||||
from utils import enumerate
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Exceptions
|
||||
#==============================================================================
|
||||
class InvalidXMLError(Exception): pass
|
||||
|
||||
class ParserError(Exception): pass
|
||||
|
||||
class InvalidContextError(ParserError): pass
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# GCCXMLParser
|
||||
#==============================================================================
|
||||
class GCCXMLParser(object):
|
||||
'Parse a GCC_XML file and extract the top-level declarations.'
|
||||
|
||||
interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0}
|
||||
|
||||
def Parse(self, filename):
|
||||
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]
|
||||
if decl is None:
|
||||
try:
|
||||
self.ParseElement(id, element)
|
||||
except InvalidContextError:
|
||||
pass # ignore those nodes with invalid context
|
||||
# (workaround gccxml bug)
|
||||
|
||||
|
||||
def Declarations(self):
|
||||
return self.declarations
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def ParseElement(self, id, element):
|
||||
method = 'Parse' + element.tag
|
||||
if hasattr(self, method):
|
||||
func = getattr(self, method)
|
||||
func(id, element)
|
||||
else:
|
||||
self.ParseUnknown(id, element)
|
||||
|
||||
|
||||
def GetElementsFromXML(self,filename):
|
||||
'Extracts a dictionary of elements from the gcc_xml file.'
|
||||
|
||||
tree = ElementTree()
|
||||
try:
|
||||
tree.parse(filename)
|
||||
except ExpatError:
|
||||
raise InvalidXMLError, 'Not a XML file: %s' % filename
|
||||
|
||||
root = tree.getroot()
|
||||
if root.tag != 'GCC_XML':
|
||||
raise InvalidXMLError, 'Not a valid GCC_XML file'
|
||||
|
||||
# build a dictionary of id -> element, None
|
||||
elementlist = root.getchildren()
|
||||
elements = {}
|
||||
for element in elementlist:
|
||||
id = element.get('id')
|
||||
if id:
|
||||
elements[id] = element, None
|
||||
return elements
|
||||
|
||||
|
||||
def GetDecl(self, id):
|
||||
if id not in self.elements:
|
||||
if id == '_0':
|
||||
raise InvalidContextError, 'Invalid context found in the xml file.'
|
||||
else:
|
||||
msg = 'ID not found in elements: %s' % id
|
||||
raise ParserError, msg
|
||||
|
||||
elem, decl = self.elements[id]
|
||||
if decl is None:
|
||||
self.ParseElement(id, elem)
|
||||
elem, decl = self.elements[id]
|
||||
if decl is None:
|
||||
raise ParserError, 'Could not parse element: %s' % elem.tag
|
||||
return decl
|
||||
|
||||
|
||||
def GetType(self, id):
|
||||
def Check(id, feature):
|
||||
pos = id.find(feature)
|
||||
if pos != -1:
|
||||
id = id[:pos] + id[pos+1:]
|
||||
return True, id
|
||||
else:
|
||||
return False, id
|
||||
const, id = Check(id, 'c')
|
||||
volatile, id = Check(id, 'v')
|
||||
restricted, id = Check(id, 'r')
|
||||
decl = self.GetDecl(id)
|
||||
if isinstance(decl, Type):
|
||||
res = deepcopy(decl)
|
||||
if const:
|
||||
res.const = const
|
||||
if volatile:
|
||||
res.volatile = volatile
|
||||
if restricted:
|
||||
res.restricted = restricted
|
||||
else:
|
||||
res = Type(decl.FullName(), const)
|
||||
res.volatile = volatile
|
||||
res.restricted = restricted
|
||||
return res
|
||||
|
||||
|
||||
def GetLocation(self, location):
|
||||
file, line = location.split(':')
|
||||
file = self.GetDecl(file)
|
||||
return file, int(line)
|
||||
|
||||
|
||||
def Update(self, id, decl):
|
||||
element, _ = self.elements[id]
|
||||
self.elements[id] = element, decl
|
||||
|
||||
|
||||
def ParseUnknown(self, id, element):
|
||||
name = '__Unknown_Element_%s' % id
|
||||
decl = Unknown(name)
|
||||
self.Update(id, decl)
|
||||
|
||||
|
||||
def ParseNamespace(self, id, element):
|
||||
namespace = element.get('name')
|
||||
context = element.get('context')
|
||||
if context:
|
||||
outer = self.GetDecl(context)
|
||||
if not outer.endswith('::'):
|
||||
outer += '::'
|
||||
namespace = outer + namespace
|
||||
if namespace.startswith('::'):
|
||||
namespace = namespace[2:]
|
||||
self.Update(id, namespace)
|
||||
|
||||
|
||||
def ParseFile(self, id, element):
|
||||
filename = element.get('name')
|
||||
self.Update(id, filename)
|
||||
|
||||
|
||||
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.
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, Class):
|
||||
self.ParseField(id, element)
|
||||
elem, decl = self.elements[id]
|
||||
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
|
||||
self.AddDecl(variable)
|
||||
self.Update(id, variable)
|
||||
|
||||
|
||||
def GetArguments(self, element):
|
||||
args = []
|
||||
for child in element:
|
||||
if child.tag == 'Argument':
|
||||
type = self.GetType(child.get('type'))
|
||||
type.default = child.get('default')
|
||||
args.append(type)
|
||||
return args
|
||||
|
||||
|
||||
def GetExceptions(self, exception_list):
|
||||
if exception_list is None:
|
||||
return None
|
||||
|
||||
exceptions = []
|
||||
for t in exception_list.split():
|
||||
exceptions.append(self.GetType(t))
|
||||
|
||||
return exceptions
|
||||
|
||||
|
||||
def ParseFunction(self, id, element, functionType=Function):
|
||||
'''functionType is used because a Operator is identical to a normal
|
||||
function, only the type of the function changes.'''
|
||||
name = element.get('name')
|
||||
returns = self.GetType(element.get('returns'))
|
||||
namespace = self.GetDecl(element.get('context'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
incomplete = bool(int(element.get('incomplete', 0)))
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
function = functionType(name, namespace, returns, params, throws)
|
||||
function.location = location
|
||||
self.AddDecl(function)
|
||||
self.Update(id, function)
|
||||
|
||||
|
||||
def ParseOperatorFunction(self, id, element):
|
||||
self.ParseFunction(id, element, Operator)
|
||||
|
||||
|
||||
def GetHierarchy(self, bases):
|
||||
'''Parses the string "bases" from the xml into a list of tuples of Base
|
||||
instances. The first tuple is the most direct inheritance, and then it
|
||||
goes up in the hierarchy.
|
||||
'''
|
||||
|
||||
if bases is None:
|
||||
return []
|
||||
base_names = bases.split()
|
||||
this_level = []
|
||||
next_levels = []
|
||||
for base in base_names:
|
||||
# get the visibility
|
||||
split = base.split(':')
|
||||
if len(split) == 2:
|
||||
visib = split[0]
|
||||
base = split[1]
|
||||
else:
|
||||
visib = Scope.public
|
||||
decl = self.GetDecl(base)
|
||||
if not isinstance(decl, Class):
|
||||
# on windows, there are some classes which "bases" points to an
|
||||
# "Unimplemented" tag, but we are not interested in this classes
|
||||
# anyway
|
||||
continue
|
||||
base = Base(decl.FullName(), visib)
|
||||
this_level.append(base)
|
||||
# normalize with the other levels
|
||||
for index, level in enumerate(decl.hierarchy):
|
||||
if index < len(next_levels):
|
||||
next_levels[index] = next_levels[index] + level
|
||||
else:
|
||||
next_levels.append(level)
|
||||
hierarchy = []
|
||||
if this_level:
|
||||
hierarchy.append(tuple(this_level))
|
||||
if next_levels:
|
||||
hierarchy.extend(next_levels)
|
||||
return hierarchy
|
||||
|
||||
|
||||
def GetMembers(self, member_list):
|
||||
# members must be a string with the ids of the members
|
||||
if member_list is None:
|
||||
return []
|
||||
members = []
|
||||
for member in member_list.split():
|
||||
decl = self.GetDecl(member)
|
||||
if type(decl) in Class.ValidMemberTypes():
|
||||
members.append(decl)
|
||||
return members
|
||||
|
||||
|
||||
def ParseClass(self, id, element):
|
||||
name = element.get('name')
|
||||
abstract = bool(int(element.get('abstract', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
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)
|
||||
class_.incomplete = incomplete
|
||||
# we have to add the declaration of the class before trying
|
||||
# to parse its members and bases, to avoid recursion.
|
||||
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]
|
||||
members = self.GetMembers(element.get('members'))
|
||||
for member in members:
|
||||
class_.AddMember(member)
|
||||
|
||||
|
||||
def ParseStruct(self, id, element):
|
||||
self.ParseClass(id, element)
|
||||
|
||||
|
||||
FUNDAMENTAL_RENAME = {
|
||||
'long long int' : 'boost::int64_t',
|
||||
'long long unsigned int' : 'boost::uint64_t',
|
||||
}
|
||||
|
||||
def ParseFundamentalType(self, id, element):
|
||||
name = element.get('name')
|
||||
name = self.FUNDAMENTAL_RENAME.get(name, name)
|
||||
type_ = FundamentalType(name)
|
||||
self.Update(id, type_)
|
||||
|
||||
|
||||
def ParseArrayType(self, id, element):
|
||||
type = self.GetType(element.get('type'))
|
||||
min = element.get('min')
|
||||
max = element.get('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, 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, expand, type.suffix)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
def ParseFunctionType(self, id, element):
|
||||
result = self.GetType(element.get('returns'))
|
||||
args = self.GetArguments(element)
|
||||
func = FunctionType(result, args)
|
||||
self.Update(id, func)
|
||||
|
||||
|
||||
def ParseMethodType(self, id, element):
|
||||
class_ = self.GetDecl(element.get('basetype')).FullName()
|
||||
result = self.GetType(element.get('returns'))
|
||||
args = self.GetArguments(element)
|
||||
method = MethodType(result, args, class_)
|
||||
self.Update(id, method)
|
||||
|
||||
|
||||
def ParseField(self, id, element):
|
||||
name = element.get('name')
|
||||
visib = element.get('access', Scope.public)
|
||||
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
|
||||
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()
|
||||
visib = element.get('access', Scope.public)
|
||||
static = bool(int(element.get('static', '0')))
|
||||
virtual = bool(int(element.get('virtual', '0')))
|
||||
abstract = bool(int(element.get('pure_virtual', '0')))
|
||||
const = bool(int(element.get('const', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
params = self.GetArguments(element)
|
||||
method = methodType(
|
||||
name, classname, result, params, visib, virtual, abstract, static, const, throws)
|
||||
method.location = location
|
||||
self.Update(id, method)
|
||||
|
||||
|
||||
def ParseOperatorMethod(self, id, element):
|
||||
self.ParseMethod(id, element, ClassOperator)
|
||||
|
||||
|
||||
def ParseConstructor(self, id, element):
|
||||
name = element.get('name')
|
||||
visib = element.get('access', Scope.public)
|
||||
classname = self.GetDecl(element.get('context')).FullName()
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
artificial = element.get('artificial', False)
|
||||
ctor = Constructor(name, classname, params, visib)
|
||||
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()
|
||||
virtual = bool(int(element.get('virtual', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
des = Destructor(name, classname, visib, virtual)
|
||||
des.location = location
|
||||
self.Update(id, des)
|
||||
|
||||
|
||||
def ParseConverter(self, id, element):
|
||||
self.ParseMethod(id, element, ConverterOperator)
|
||||
|
||||
|
||||
def ParseTypedef(self, id, element):
|
||||
name = element.get('name')
|
||||
type = self.GetType(element.get('type'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, Class):
|
||||
context = context.FullName()
|
||||
typedef = Typedef(type, name, context)
|
||||
self.Update(id, typedef)
|
||||
self.AddDecl(typedef)
|
||||
|
||||
|
||||
def ParseEnumeration(self, id, element):
|
||||
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)
|
||||
self.AddDecl(enum)
|
||||
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.incomplete = incomplete
|
||||
self.Update(id, enum)
|
||||
|
||||
|
||||
|
||||
def ParseDeclarations(filename):
|
||||
'Returns a list of the top declarations found in the gcc_xml file.'
|
||||
|
||||
parser = GCCXMLParser()
|
||||
parser.Parse(filename)
|
||||
return parser.Declarations()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ParseDeclarations(r'D:\Programming\Libraries\boost-cvs\boost\libs\python\pyste\example\test.xml')
|
||||
@@ -1,81 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Exporter import Exporter
|
||||
from ClassExporter import ClassExporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from VarExporter import VarExporter
|
||||
from infos import *
|
||||
from declarations import *
|
||||
import os.path
|
||||
import exporters
|
||||
import MultipleCodeUnit
|
||||
|
||||
#==============================================================================
|
||||
# HeaderExporter
|
||||
#==============================================================================
|
||||
class HeaderExporter(Exporter):
|
||||
'Exports all declarations found in the given header'
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
pass
|
||||
|
||||
|
||||
def IsInternalName(self, name):
|
||||
'''Returns true if the given name looks like a internal compiler
|
||||
structure'''
|
||||
return name.startswith('_')
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
header = os.path.normpath(self.parser_header)
|
||||
for decl in self.declarations:
|
||||
# check if this declaration is in the header
|
||||
location = os.path.abspath(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)
|
||||
|
||||
|
||||
def HandleDeclaration(self, decl, codeunit, exported_names):
|
||||
'''Dispatch the declaration to the appropriate method, that must create
|
||||
a suitable info object for a Exporter, create a Exporter, set its
|
||||
declarations and append it to the list of exporters.
|
||||
'''
|
||||
dispatch_table = {
|
||||
Class : ClassExporter,
|
||||
Enumeration : EnumExporter,
|
||||
Function : FunctionExporter,
|
||||
Variable : VarExporter,
|
||||
}
|
||||
|
||||
exporter_class = dispatch_table.get(type(decl))
|
||||
if exporter_class is not None:
|
||||
self.HandleExporter(decl, exporter_class, codeunit, exported_names)
|
||||
|
||||
|
||||
def HandleExporter(self, decl, exporter_type, codeunit, exported_names):
|
||||
# only export complete declarations
|
||||
if not decl.incomplete:
|
||||
info = self.info[decl.name]
|
||||
info.name = decl.FullName()
|
||||
info.include = self.info.include
|
||||
exporter = exporter_type(info)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
exporter.SetParsedHeader(self.parser_header)
|
||||
if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit):
|
||||
codeunit.SetCurrent(self.interface_file, exporter.Name())
|
||||
else:
|
||||
codeunit.SetCurrent(exporter.Name())
|
||||
exporter.GenerateCode(codeunit, exported_names)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.include
|
||||
@@ -1,135 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
import os
|
||||
import utils
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MultipleCodeUnit
|
||||
#==============================================================================
|
||||
class MultipleCodeUnit(object):
|
||||
'''
|
||||
Represents a bunch of cpp files, where each cpp file represents a header
|
||||
to be exported by pyste. Another cpp, named <module>.cpp is created too.
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, outdir):
|
||||
self.modulename = modulename
|
||||
self.outdir = outdir
|
||||
self.codeunits = {} # maps from a (filename, function) to a SingleCodeUnit
|
||||
self.functions = []
|
||||
self._current = None
|
||||
self.all = SingleCodeUnit(None, None)
|
||||
|
||||
|
||||
def _FunctionName(self, interface_file):
|
||||
name = os.path.splitext(interface_file)[0]
|
||||
return 'Export_%s' % utils.makeid(name)
|
||||
|
||||
|
||||
def _FileName(self, interface_file):
|
||||
filename = os.path.basename(interface_file)
|
||||
filename = '_%s.cpp' % os.path.splitext(filename)[0]
|
||||
return os.path.join(self.outdir, filename)
|
||||
|
||||
|
||||
def SetCurrent(self, interface_file, export_name):
|
||||
'Changes the current code unit'
|
||||
if export_name is None:
|
||||
self._current = None
|
||||
elif export_name is '__all__':
|
||||
self._current = self.all
|
||||
else:
|
||||
filename = self._FileName(interface_file)
|
||||
function = self._FunctionName(interface_file)
|
||||
try:
|
||||
codeunit = self.codeunits[filename]
|
||||
except KeyError:
|
||||
codeunit = SingleCodeUnit(None, filename)
|
||||
codeunit.module_definition = 'void %s()' % function
|
||||
self.codeunits[filename] = codeunit
|
||||
if function not in self.functions:
|
||||
self.functions.append(function)
|
||||
self._current = codeunit
|
||||
|
||||
|
||||
def Current(self):
|
||||
return self._current
|
||||
|
||||
current = property(Current, SetCurrent)
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
if self._current is not None:
|
||||
self.current.Write(section, code)
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
if self._current is not None:
|
||||
return self.current.Section(section)
|
||||
|
||||
|
||||
def _CreateOutputDir(self):
|
||||
try:
|
||||
os.mkdir(self.outdir)
|
||||
except OSError: pass # already created
|
||||
|
||||
|
||||
def Save(self):
|
||||
# create the directory where all the files will go
|
||||
self._CreateOutputDir();
|
||||
# order all code units by filename, and merge them all
|
||||
codeunits = {} # filename => list of codeunits
|
||||
|
||||
# While ordering all code units by file name, the first code
|
||||
# unit in the list of code units is used as the main unit
|
||||
# which dumps all the include, declaration and
|
||||
# declaration-outside sections at the top of the file.
|
||||
for filename, codeunit in self.codeunits.items():
|
||||
if filename not in codeunits:
|
||||
# this codeunit is the main codeunit.
|
||||
codeunits[filename] = [codeunit]
|
||||
codeunit.Merge(self.all)
|
||||
else:
|
||||
main_unit = codeunits[filename][0]
|
||||
for section in ('include', 'declaration', 'declaration-outside'):
|
||||
main_unit.code[section] = main_unit.code[section] + codeunit.code[section]
|
||||
codeunit.code[section] = ''
|
||||
codeunits[filename].append(codeunit)
|
||||
|
||||
# Now write all the codeunits appending them correctly.
|
||||
for file_units in codeunits.values():
|
||||
append = False
|
||||
for codeunit in file_units:
|
||||
codeunit.Save(append)
|
||||
if not append:
|
||||
append = True
|
||||
|
||||
|
||||
def GenerateMain(self, interfaces):
|
||||
# generate the main cpp
|
||||
filename = os.path.join(self.outdir, '_main.cpp')
|
||||
fout = SmartFile(filename, 'w')
|
||||
fout.write(utils.left_equals('Include'))
|
||||
fout.write('#include <boost/python/module.hpp>\n\n')
|
||||
fout.write(utils.left_equals('Exports'))
|
||||
functions = [self._FunctionName(x) for x in interfaces]
|
||||
for function in functions:
|
||||
fout.write('void %s();\n' % function)
|
||||
fout.write('\n')
|
||||
fout.write(utils.left_equals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
|
||||
fout.write('{\n')
|
||||
indent = ' ' * 4
|
||||
for function in functions:
|
||||
fout.write(indent)
|
||||
fout.write('%s();\n' % function)
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from settings import namespaces
|
||||
import settings
|
||||
from utils import remove_duplicated_lines, left_equals
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# SingleCodeUnit
|
||||
#==============================================================================
|
||||
class SingleCodeUnit:
|
||||
'''
|
||||
Represents a cpp file, where other objects can write in one of the
|
||||
predefined sections.
|
||||
The avaiable sections are:
|
||||
pchinclude - The pre-compiled header area
|
||||
include - The include area of the cpp file
|
||||
declaration - The part before the module definition
|
||||
module - Inside the BOOST_PYTHON_MODULE macro
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, filename):
|
||||
self.modulename = modulename
|
||||
self.filename = filename
|
||||
# define the avaiable sections
|
||||
self.code = {}
|
||||
# include section
|
||||
self.code['pchinclude'] = ''
|
||||
# include section
|
||||
self.code['include'] = ''
|
||||
# declaration section (inside namespace)
|
||||
self.code['declaration'] = ''
|
||||
# declaration (outside namespace)
|
||||
self.code['declaration-outside'] = ''
|
||||
# inside BOOST_PYTHON_MACRO
|
||||
self.code['module'] = ''
|
||||
# create the default module definition
|
||||
self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
'write the given code in the section of the code unit'
|
||||
if section not in self.code:
|
||||
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
|
||||
self.code[section] += code
|
||||
|
||||
|
||||
def Merge(self, other):
|
||||
for section in ('include', 'declaration', 'declaration-outside', 'module'):
|
||||
self.code[section] = self.code[section] + other.code[section]
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def SetCurrent(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
def Current(self):
|
||||
pass
|
||||
|
||||
|
||||
def Save(self, append=False):
|
||||
'Writes this code unit to the filename'
|
||||
space = '\n\n'
|
||||
if not append:
|
||||
flag = 'w'
|
||||
else:
|
||||
flag = 'a'
|
||||
fout = SmartFile(self.filename, flag)
|
||||
fout.write('\n')
|
||||
# includes
|
||||
# boost.python header
|
||||
if self.code['pchinclude']:
|
||||
fout.write(left_equals('PCH'))
|
||||
fout.write(self.code['pchinclude']+'\n')
|
||||
fout.write('#ifdef _MSC_VER\n')
|
||||
fout.write('#pragma hdrstop\n')
|
||||
fout.write('#endif\n')
|
||||
else:
|
||||
fout.write(left_equals('Boost Includes'))
|
||||
fout.write('#include <boost/python.hpp>\n')
|
||||
# include numerical boost for int64 definitions
|
||||
fout.write('#include <boost/cstdint.hpp>\n')
|
||||
fout.write('\n')
|
||||
# other includes
|
||||
if self.code['include']:
|
||||
fout.write(left_equals('Includes'))
|
||||
includes = remove_duplicated_lines(self.code['include'])
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
# using
|
||||
if settings.USING_BOOST_NS and not append:
|
||||
fout.write(left_equals('Using'))
|
||||
fout.write('using namespace boost::python;\n\n')
|
||||
# declarations
|
||||
declaration = self.code['declaration']
|
||||
declaration_outside = self.code['declaration-outside']
|
||||
if declaration_outside or declaration:
|
||||
fout.write(left_equals('Declarations'))
|
||||
if declaration_outside:
|
||||
fout.write(declaration_outside + '\n\n')
|
||||
if declaration:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write('namespace %s {\n\n' % pyste_namespace)
|
||||
fout.write(declaration)
|
||||
fout.write('\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(left_equals('Module'))
|
||||
fout.write(self.module_definition + '\n')
|
||||
fout.write('{\n')
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n\n')
|
||||
fout.close()
|
||||
@@ -1,60 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os
|
||||
import md5
|
||||
|
||||
#==============================================================================
|
||||
# SmartFile
|
||||
#==============================================================================
|
||||
class SmartFile(object):
|
||||
'''
|
||||
A file-like object used for writing files. The given file will only be
|
||||
actually written to disk if there's not a file with the same name, or if
|
||||
the existing file is *different* from the file to be written.
|
||||
'''
|
||||
|
||||
def __init__(self, filename, mode='w'):
|
||||
self.filename = filename
|
||||
self.mode = mode
|
||||
self._contents = []
|
||||
self._closed = False
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if not self._closed:
|
||||
self.close()
|
||||
|
||||
|
||||
def write(self, string):
|
||||
self._contents.append(string)
|
||||
|
||||
|
||||
def _dowrite(self, contents):
|
||||
f = file(self.filename, self.mode)
|
||||
f.write(contents)
|
||||
f.close()
|
||||
|
||||
|
||||
def _GetMD5(self, string):
|
||||
return md5.new(string).digest()
|
||||
|
||||
|
||||
def close(self):
|
||||
# if the filename doesn't exist, write the file right away
|
||||
this_contents = ''.join(self._contents)
|
||||
if not os.path.isfile(self.filename):
|
||||
self._dowrite(this_contents)
|
||||
else:
|
||||
# read the contents of the file already in disk
|
||||
f = file(self.filename)
|
||||
other_contents = f.read()
|
||||
f.close()
|
||||
# test the md5 for both files
|
||||
this_md5 = self._GetMD5(this_contents)
|
||||
other_md5 = self._GetMD5(other_contents)
|
||||
if this_md5 != other_md5:
|
||||
self._dowrite(this_contents)
|
||||
self._closed = True
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from Exporter import Exporter
|
||||
from settings import *
|
||||
import utils
|
||||
|
||||
#==============================================================================
|
||||
# VarExporter
|
||||
#==============================================================================
|
||||
class VarExporter(Exporter):
|
||||
'''Exports a global variable.
|
||||
'''
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
if self.info.exclude: return
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
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
|
||||
print
|
||||
rename = self.info.rename or self.info.name
|
||||
code = self.INDENT + namespaces.python
|
||||
code += 'scope().attr("%s") = %s;\n' % (rename, self.info.name)
|
||||
codeunit.Write('module', code)
|
||||
|
||||
|
||||
def Order(self):
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
@@ -1,653 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
'''
|
||||
Defines classes that represent declarations found in C++ header files.
|
||||
|
||||
'''
|
||||
|
||||
# version indicates the version of the declarations. Whenever a declaration
|
||||
# changes, this variable should be updated, so that the caches can be rebuilt
|
||||
# automatically
|
||||
version = '1.0'
|
||||
|
||||
#==============================================================================
|
||||
# Declaration
|
||||
#==============================================================================
|
||||
class Declaration(object):
|
||||
'''Base class for all declarations.
|
||||
@ivar name: The name of the declaration.
|
||||
@ivar namespace: The namespace of the declaration.
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
'''
|
||||
@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"
|
||||
@rtype: string
|
||||
@return: The full name of the declaration.
|
||||
'''
|
||||
namespace = self.namespace or ''
|
||||
if namespace and not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + self.name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '<Declaration %s at %s>' % (self.FullName(), id(self))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return 'Declaration of %s' % self.FullName()
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Class
|
||||
#==============================================================================
|
||||
class Class(Declaration):
|
||||
'''
|
||||
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)
|
||||
self.__members = members
|
||||
self.__member_names = {}
|
||||
self.abstract = abstract
|
||||
self.bases = ()
|
||||
self.hierarchy = ()
|
||||
self.operator = {}
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
'''iterates through the class' members.
|
||||
'''
|
||||
return iter(self.__members)
|
||||
|
||||
|
||||
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:
|
||||
continue
|
||||
constructors.append(member)
|
||||
return constructors
|
||||
|
||||
|
||||
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):
|
||||
'''Returns true if this class has a public default constructor.
|
||||
@rtype: bool
|
||||
'''
|
||||
for cons in self.Constructors():
|
||||
if cons.IsDefault():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def AddMember(self, member):
|
||||
if member.name in self.__member_names:
|
||||
member.is_unique = False
|
||||
for m in self:
|
||||
if m.name == member.name:
|
||||
m.is_unique = False
|
||||
else:
|
||||
member.is_unique = True
|
||||
self.__member_names[member.name] = 1
|
||||
self.__members.append(member)
|
||||
if isinstance(member, ClassOperator):
|
||||
self.operator[member.name] = member
|
||||
|
||||
|
||||
def ValidMemberTypes():
|
||||
return (NestedClass, Method, Constructor, Destructor, ClassVariable,
|
||||
ClassOperator, ConverterOperator, ClassEnumeration)
|
||||
ValidMemberTypes = staticmethod(ValidMemberTypes)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# NestedClass
|
||||
#==============================================================================
|
||||
class NestedClass(Class):
|
||||
'''The declaration of a class/struct inside another class/struct.
|
||||
|
||||
@type class: string
|
||||
@ivar class: fullname of the class where this class is contained.
|
||||
|
||||
@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
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'''The full name of this class, like ns::outer::inner.
|
||||
@rtype: string
|
||||
'''
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# 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.
|
||||
@ivar _result: instance of L{Type} or None.
|
||||
@ivar _parameters: list of L{Type} instances.
|
||||
@ivar _throws: exception specifiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace, result, params, throws=None):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
self.result = result
|
||||
# the parameters: instances of Type
|
||||
self.parameters = params
|
||||
# the exception specification
|
||||
self.throws = throws
|
||||
|
||||
|
||||
def Exceptions(self):
|
||||
if self.throws is None:
|
||||
return ""
|
||||
else:
|
||||
return " throw(%s)" % ', '.join ([x.FullName() for x in self.throws])
|
||||
|
||||
|
||||
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)&%s' % (result, params, self.Exceptions(), self.FullName())
|
||||
|
||||
|
||||
def MinArgs(self):
|
||||
min = 0
|
||||
for arg in self.parameters:
|
||||
if arg.default is None:
|
||||
min += 1
|
||||
return min
|
||||
|
||||
minArgs = property(MinArgs)
|
||||
|
||||
|
||||
def MaxArgs(self):
|
||||
return len(self.parameters)
|
||||
|
||||
maxArgs = property(MaxArgs)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Operator
|
||||
#==============================================================================
|
||||
class Operator(Function):
|
||||
'''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 ''
|
||||
if not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + 'operator' + self.name
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Method
|
||||
#==============================================================================
|
||||
class Method(Function):
|
||||
'''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.
|
||||
@ivar _throws: list of exception specificiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const, throws=None):
|
||||
Function.__init__(self, name, None, result, params, throws)
|
||||
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 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, force)
|
||||
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])
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s%s)&%s' %\
|
||||
(result, self.class_, params, const, self.Exceptions(), self.FullName())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Constructor
|
||||
#==============================================================================
|
||||
class Constructor(Method):
|
||||
'''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):
|
||||
'''Returns True if this constructor is a default constructor.
|
||||
'''
|
||||
return len(self.parameters) == 0 and self.visibility == Scope.public
|
||||
|
||||
|
||||
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_reference = isinstance(param, ReferenceType)
|
||||
is_public = self.visibility == Scope.public
|
||||
return param_reference and class_as_param and param.const and is_public
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# 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 PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassOperator
|
||||
#==============================================================================
|
||||
class ClassOperator(Method):
|
||||
'A custom operator in a class.'
|
||||
|
||||
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()
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Type
|
||||
#==============================================================================
|
||||
class Type(Declaration):
|
||||
'''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, suffix=''):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
self.const = const
|
||||
# used when the Type is a function argument
|
||||
self.default = default
|
||||
self.volatile = False
|
||||
self.restricted = False
|
||||
self.suffix = suffix
|
||||
|
||||
def __repr__(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return '<Type ' + const + self.name + '>'
|
||||
|
||||
|
||||
def FullName(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return const + self.name + self.suffix
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ArrayType
|
||||
#==============================================================================
|
||||
class ArrayType(Type):
|
||||
'''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, min, max):
|
||||
'min and max can be None.'
|
||||
Type.__init__(self, name, const)
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ReferenceType
|
||||
#==============================================================================
|
||||
class ReferenceType(Type):
|
||||
'''A reference type.'''
|
||||
|
||||
def __init__(self, name, const=False, default=None, expandRef=True, suffix=''):
|
||||
Type.__init__(self, name, const, default)
|
||||
if expandRef:
|
||||
self.suffix = suffix + '&'
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# PointerType
|
||||
#==============================================================================
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
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, like int, void, etc.'
|
||||
|
||||
def __init__(self, name, const=False, default=None):
|
||||
Type.__init__(self, name, const, default)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionType
|
||||
#==============================================================================
|
||||
class FunctionType(Type):
|
||||
'''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()
|
||||
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (*)' % self.result.FullName()
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MethodType
|
||||
#==============================================================================
|
||||
class MethodType(FunctionType):
|
||||
'''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_):
|
||||
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]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Variable
|
||||
#==============================================================================
|
||||
class Variable(Declaration):
|
||||
'''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)
|
||||
self.type = type
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassVariable
|
||||
#==============================================================================
|
||||
class ClassVariable(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_
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassEnumeration
|
||||
#==============================================================================
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Unknown
|
||||
#==============================================================================
|
||||
class Unknown(Declaration):
|
||||
'''A declaration that Pyste does not know how to handle.
|
||||
'''
|
||||
|
||||
def __init__(self, name):
|
||||
Declaration.__init__(self, name, None)
|
||||
@@ -1,12 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
# a list of Exporter instances
|
||||
exporters = []
|
||||
|
||||
current_interface = None # the current interface file being processed
|
||||
importing = False # whetever we are now importing a pyste file.
|
||||
# exporters created here shouldn't export themselves
|
||||
@@ -1,87 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
'''
|
||||
Various helpers for interface files.
|
||||
'''
|
||||
|
||||
from settings import *
|
||||
from policies import *
|
||||
from declarations import *
|
||||
|
||||
#==============================================================================
|
||||
# FunctionWrapper
|
||||
#==============================================================================
|
||||
class FunctionWrapper(object):
|
||||
'''Holds information about a wrapper for a function or a method. It is
|
||||
divided in 2 parts: the name of the Wrapper, and its code. The code is
|
||||
placed in the declaration section of the module, while the name is used to
|
||||
def' the function or method (with the pyste namespace prepend to it). If
|
||||
code is None, the name is left unchanged.
|
||||
'''
|
||||
|
||||
def __init__(self, name, code=None):
|
||||
self.name = name
|
||||
self.code = code
|
||||
|
||||
def FullName(self):
|
||||
if self.code:
|
||||
return namespaces.pyste + self.name
|
||||
else:
|
||||
return self.name
|
||||
|
||||
|
||||
_printed_warnings = {} # used to avoid double-prints of warnings
|
||||
|
||||
#==============================================================================
|
||||
# HandlePolicy
|
||||
#==============================================================================
|
||||
def HandlePolicy(function, policy):
|
||||
'''Show a warning to the user if the function needs a policy and doesn't
|
||||
have one. Return a policy to the function, which is the given policy itself
|
||||
if it is not None, or a default policy for this method.
|
||||
'''
|
||||
|
||||
def IsString(type):
|
||||
'Return True if the Type instance can be considered a string'
|
||||
return type.FullName() == 'const char*'
|
||||
|
||||
def IsPyObject(type):
|
||||
return type.FullName() == '_object *' # internal name of PyObject
|
||||
|
||||
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):
|
||||
policy = return_value_policy(copy_const_reference)
|
||||
# basic test if the result type demands a policy
|
||||
needs_policy = isinstance(result, (ReferenceType, PointerType))
|
||||
# show a warning to the user, if needed
|
||||
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()
|
||||
if warning not in _printed_warnings:
|
||||
print warning
|
||||
print
|
||||
# avoid double prints of the same warning
|
||||
_printed_warnings[warning] = 1
|
||||
return policy
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# EspecializeTypeID
|
||||
#==============================================================================
|
||||
_exported_type_ids = {}
|
||||
def EspecializeTypeID(typename):
|
||||
global _exported_type_ids
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)\n' % typename
|
||||
if macro not in _exported_type_ids:
|
||||
_exported_type_ids[macro] = 1
|
||||
return macro
|
||||
else:
|
||||
return None
|
||||
@@ -1,259 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os.path
|
||||
import copy
|
||||
import exporters
|
||||
from ClassExporter import ClassExporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
from VarExporter import VarExporter
|
||||
from CodeExporter import CodeExporter
|
||||
from exporterutils import FunctionWrapper
|
||||
from utils import makeid
|
||||
import warnings
|
||||
|
||||
#==============================================================================
|
||||
# DeclarationInfo
|
||||
#==============================================================================
|
||||
class DeclarationInfo:
|
||||
|
||||
def __init__(self, otherInfo=None):
|
||||
self.__infos = {}
|
||||
self.__attributes = {}
|
||||
if otherInfo is not None:
|
||||
self.__infos = copy.deepcopy(otherInfo.__infos)
|
||||
self.__attributes = copy.deepcopy(otherInfo.__attributes)
|
||||
|
||||
|
||||
def __getitem__(self, name):
|
||||
'Used to access sub-infos'
|
||||
if name.startswith('__'):
|
||||
raise AttributeError
|
||||
default = DeclarationInfo()
|
||||
default._Attribute('name', name)
|
||||
return self.__infos.setdefault(name, default)
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self[name]
|
||||
|
||||
|
||||
def _Attribute(self, name, value=None):
|
||||
if value is None:
|
||||
# get value
|
||||
return self.__attributes.get(name)
|
||||
else:
|
||||
# set value
|
||||
self.__attributes[name] = value
|
||||
|
||||
|
||||
def AddExporter(self, exporter):
|
||||
# this was causing a much serious bug, as reported by Niall Douglas:
|
||||
# another solution must be found!
|
||||
#if not exporters.importing:
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionInfo
|
||||
#==============================================================================
|
||||
class FunctionInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, tail=None, otherOption=None,
|
||||
exporter_class = FunctionExporter):
|
||||
DeclarationInfo.__init__(self, otherOption)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
self._Attribute('exclude', False)
|
||||
# create a FunctionExporter
|
||||
exporter = exporter_class(InfoWrapper(self), tail)
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassInfo
|
||||
#==============================================================================
|
||||
class ClassInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, tail=None, otherInfo=None,
|
||||
exporter_class = ClassExporter):
|
||||
DeclarationInfo.__init__(self, otherInfo)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
self._Attribute('exclude', False)
|
||||
# create a ClassExporter
|
||||
exporter = exporter_class(InfoWrapper(self), tail)
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# templates
|
||||
#==============================================================================
|
||||
def GenerateName(name, type_list):
|
||||
name = name.replace('::', '_')
|
||||
names = [name] + type_list
|
||||
return makeid('_'.join(names))
|
||||
|
||||
|
||||
class ClassTemplateInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include,
|
||||
exporter_class = ClassExporter):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
self._exporter_class = exporter_class
|
||||
|
||||
|
||||
def Instantiate(self, type_list, rename=None):
|
||||
if not rename:
|
||||
rename = GenerateName(self._Attribute('name'), type_list)
|
||||
# generate code to instantiate the template
|
||||
types = ', '.join(type_list)
|
||||
tail = 'typedef %s< %s > %s;\n' % (self._Attribute('name'), types, rename)
|
||||
tail += 'void __instantiate_%s()\n' % rename
|
||||
tail += '{ sizeof(%s); }\n\n' % rename
|
||||
# create a ClassInfo
|
||||
class_ = ClassInfo(rename, self._Attribute('include'), tail, self,
|
||||
exporter_class = self._exporter_class)
|
||||
return class_
|
||||
|
||||
|
||||
def __call__(self, types, rename=None):
|
||||
if isinstance(types, str):
|
||||
types = types.split()
|
||||
return self.Instantiate(types, rename)
|
||||
|
||||
#==============================================================================
|
||||
# EnumInfo
|
||||
#==============================================================================
|
||||
class EnumInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, exporter_class = EnumExporter):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
self._Attribute('exclude', False)
|
||||
self._Attribute('export_values', False)
|
||||
exporter = exporter_class(InfoWrapper(self))
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# HeaderInfo
|
||||
#==============================================================================
|
||||
class HeaderInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, include, exporter_class = HeaderExporter):
|
||||
warnings.warn('AllFromHeader is not working in all cases in the current version.')
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = exporter_class(InfoWrapper(self))
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# VarInfo
|
||||
#==============================================================================
|
||||
class VarInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, exporter_class = VarExporter):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
exporter = exporter_class(InfoWrapper(self))
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CodeInfo
|
||||
#==============================================================================
|
||||
class CodeInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, code, section, exporter_class = CodeExporter):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('code', code)
|
||||
self._Attribute('section', section)
|
||||
exporter = exporter_class(InfoWrapper(self))
|
||||
self.AddExporter(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# InfoWrapper
|
||||
#==============================================================================
|
||||
class InfoWrapper:
|
||||
'Provides a nicer interface for a info'
|
||||
|
||||
def __init__(self, info):
|
||||
self.__dict__['_info'] = info # so __setattr__ is not called
|
||||
|
||||
def __getitem__(self, name):
|
||||
return InfoWrapper(self._info[name])
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._info._Attribute(name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self._info._Attribute(name, value)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Functions
|
||||
#==============================================================================
|
||||
def exclude(info):
|
||||
info._Attribute('exclude', True)
|
||||
|
||||
def set_policy(info, policy):
|
||||
info._Attribute('policy', policy)
|
||||
|
||||
def rename(info, name):
|
||||
info._Attribute('rename', name)
|
||||
|
||||
def set_wrapper(info, wrapper):
|
||||
if isinstance(wrapper, str):
|
||||
wrapper = FunctionWrapper(wrapper)
|
||||
info._Attribute('wrapper', wrapper)
|
||||
|
||||
def instantiate(template, types, rename=None):
|
||||
if isinstance(types, str):
|
||||
types = types.split()
|
||||
return template.Instantiate(types, rename)
|
||||
|
||||
def use_shared_ptr(info):
|
||||
info._Attribute('smart_ptr', 'boost::shared_ptr< %s >')
|
||||
|
||||
def use_auto_ptr(info):
|
||||
info._Attribute('smart_ptr', 'std::auto_ptr< %s >')
|
||||
|
||||
def holder(info, function):
|
||||
msg = "Expected a callable that accepts one string argument."
|
||||
assert callable(function), msg
|
||||
info._Attribute('holder', function)
|
||||
|
||||
def add_method(info, name, rename=None):
|
||||
added = info._Attribute('__added__')
|
||||
if added is None:
|
||||
info._Attribute('__added__', [(name, rename)])
|
||||
else:
|
||||
added.append((name, rename))
|
||||
|
||||
|
||||
def class_code(info, code):
|
||||
added = info._Attribute('__code__')
|
||||
if added is None:
|
||||
info._Attribute('__code__', [code])
|
||||
else:
|
||||
added.append(code)
|
||||
|
||||
def final(info):
|
||||
info._Attribute('no_override', True)
|
||||
|
||||
|
||||
def export_values(info):
|
||||
info._Attribute('export_values', True)
|
||||
@@ -1,95 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
class Policy(object):
|
||||
'Represents one of the call policies of boost.python.'
|
||||
|
||||
def __init__(self):
|
||||
if type(self) is Policy:
|
||||
raise RuntimeError, "Can't create an instance of the class Policy"
|
||||
|
||||
|
||||
def Code(self):
|
||||
'Returns the string corresponding to a instancialization of the policy.'
|
||||
pass
|
||||
|
||||
|
||||
def _next(self):
|
||||
if self.next is not None:
|
||||
return ', %s >' % self.next.Code()
|
||||
else:
|
||||
return ' >'
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.Code() == other.Code()
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
class return_internal_reference(Policy):
|
||||
'Ties the return value to one of the parameters.'
|
||||
|
||||
def __init__(self, param=1, next=None):
|
||||
'''
|
||||
param is the position of the parameter, or None for "self".
|
||||
next indicates the next policy, or None.
|
||||
'''
|
||||
self.param = param
|
||||
self.next=next
|
||||
|
||||
|
||||
def Code(self):
|
||||
c = 'return_internal_reference< %i' % self.param
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
|
||||
|
||||
class with_custodian_and_ward(Policy):
|
||||
'Ties lifetime of two arguments of a function.'
|
||||
|
||||
def __init__(self, custodian, ward, next=None):
|
||||
self.custodian = custodian
|
||||
self.ward = ward
|
||||
self.next = next
|
||||
|
||||
def Code(self):
|
||||
c = 'with_custodian_and_ward< %i, %i' % (self.custodian, self.ward)
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
|
||||
|
||||
class return_value_policy(Policy):
|
||||
'Policy to convert return values.'
|
||||
|
||||
def __init__(self, which, next=None):
|
||||
self.which = which
|
||||
self.next = next
|
||||
|
||||
|
||||
def Code(self):
|
||||
c = 'return_value_policy< %s' % self.which
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
class return_self(Policy):
|
||||
|
||||
def Code(self):
|
||||
return 'return_self<>'
|
||||
|
||||
|
||||
# values for return_value_policy
|
||||
reference_existing_object = 'reference_existing_object'
|
||||
copy_const_reference = 'copy_const_reference'
|
||||
copy_non_const_reference = 'copy_non_const_reference'
|
||||
manage_new_object = 'manage_new_object'
|
||||
return_opaque_pointer = 'return_opaque_pointer'
|
||||
return_by_value = 'return_by_value'
|
||||
@@ -1,424 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
"""
|
||||
Pyste version %s
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> The name of the module that will be generated;
|
||||
defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> Add an include path
|
||||
-D <symbol> Define symbol
|
||||
--multiple Create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out=<name> Specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using Do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> Set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug Writes the xml for each file parsed in the current
|
||||
directory
|
||||
--cache-dir=<dir> Directory for cache files (speeds up future runs)
|
||||
--only-create-cache Recreates all caches (doesn't generate code).
|
||||
--generate-main Generates the _main.cpp file (in multiple mode)
|
||||
--file-list A file with one pyste file per line. Use as a
|
||||
substitute for passing the files in the command
|
||||
line.
|
||||
--gccxml-path=<path> Path to gccxml executable (default: gccxml)
|
||||
--no-default-include Do not use INCLUDE environment variable for include
|
||||
files to pass along gccxml.
|
||||
-h, --help Print this help and exit
|
||||
-v, --version Print version information
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import exporters
|
||||
import SingleCodeUnit
|
||||
import MultipleCodeUnit
|
||||
import infos
|
||||
import exporterutils
|
||||
import settings
|
||||
import gc
|
||||
import sys
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
import time
|
||||
import declarations
|
||||
|
||||
__version__ = '0.9.30'
|
||||
|
||||
def RecursiveIncludes(include):
|
||||
'Return a list containg the include dir and all its subdirectories'
|
||||
dirs = [include]
|
||||
def visit(arg, dir, names):
|
||||
# ignore CVS dirs
|
||||
if os.path.split(dir)[1] != 'CVS':
|
||||
dirs.append(dir)
|
||||
os.path.walk(include, visit, None)
|
||||
return dirs
|
||||
|
||||
|
||||
def GetDefaultIncludes():
|
||||
if 'INCLUDE' in os.environ:
|
||||
include = os.environ['INCLUDE']
|
||||
return include.split(os.pathsep)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def ProcessIncludes(includes):
|
||||
if sys.platform == 'win32':
|
||||
index = 0
|
||||
for include in includes:
|
||||
includes[index] = include.replace('\\', '/')
|
||||
index += 1
|
||||
|
||||
|
||||
def ReadFileList(filename):
|
||||
f = file(filename)
|
||||
files = []
|
||||
try:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
files.append(line)
|
||||
finally:
|
||||
f.close()
|
||||
return files
|
||||
|
||||
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__ % __version__
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
options, files = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'R:I:D:vh',
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=',
|
||||
'only-create-cache', 'version', 'generate-main', 'file-list=', 'help',
|
||||
'gccxml-path=', 'no-default-include'])
|
||||
except getopt.GetoptError, e:
|
||||
print
|
||||
print 'ERROR:', e
|
||||
Usage()
|
||||
|
||||
default_includes = GetDefaultIncludes()
|
||||
includes = []
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
multiple = False
|
||||
cache_dir = None
|
||||
create_cache = False
|
||||
generate_main = False
|
||||
gccxml_path = 'gccxml'
|
||||
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
elif opt == '-D':
|
||||
defines.append(value)
|
||||
elif opt == '-R':
|
||||
includes.extend(RecursiveIncludes(value))
|
||||
elif opt == '--module':
|
||||
module = value
|
||||
elif opt == '--out':
|
||||
out = value
|
||||
elif opt == '--no-using':
|
||||
settings.namespaces.python = 'boost::python::'
|
||||
settings.USING_BOOST_NS = False
|
||||
elif opt == '--pyste-ns':
|
||||
settings.namespaces.pyste = value + '::'
|
||||
elif opt == '--debug':
|
||||
settings.DEBUG = True
|
||||
elif opt == '--multiple':
|
||||
multiple = True
|
||||
elif opt == '--cache-dir':
|
||||
cache_dir = value
|
||||
elif opt == '--only-create-cache':
|
||||
create_cache = True
|
||||
elif opt == '--file-list':
|
||||
files += ReadFileList(value)
|
||||
elif opt in ['-h', '--help']:
|
||||
Usage()
|
||||
elif opt in ['-v', '--version']:
|
||||
print 'Pyste version %s' % __version__
|
||||
sys.exit(2)
|
||||
elif opt == '--generate-main':
|
||||
generate_main = True
|
||||
elif opt == '--gccxml-path':
|
||||
gccxml_path = value
|
||||
elif opt == '--no-default-include':
|
||||
default_includes = []
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
|
||||
includes[0:0] = default_includes
|
||||
if not files:
|
||||
Usage()
|
||||
if not module:
|
||||
module = os.path.splitext(os.path.basename(files[0]))[0]
|
||||
if not out:
|
||||
out = module
|
||||
if not multiple:
|
||||
out += '.cpp'
|
||||
for file in files:
|
||||
d = os.path.dirname(os.path.abspath(file))
|
||||
if d not in sys.path:
|
||||
sys.path.append(d)
|
||||
|
||||
if create_cache and not cache_dir:
|
||||
print 'Error: Use --cache-dir to indicate where to create the cache files!'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
if generate_main and not multiple:
|
||||
print 'Error: --generate-main only valid in multiple mode.'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
ProcessIncludes(includes)
|
||||
return includes, defines, module, out, files, multiple, cache_dir, create_cache, \
|
||||
generate_main, gccxml_path
|
||||
|
||||
|
||||
def PCHInclude(*headers):
|
||||
code = '\n'.join(['#include <%s>' % x for x in headers])
|
||||
infos.CodeInfo(code, 'pchinclude')
|
||||
|
||||
|
||||
def CreateContext():
|
||||
'create the context where a interface file will be executed'
|
||||
context = {}
|
||||
context['Import'] = Import
|
||||
# infos
|
||||
context['Function'] = infos.FunctionInfo
|
||||
context['Class'] = infos.ClassInfo
|
||||
context['Include'] = lambda header: infos.CodeInfo('#include <%s>\n' % header, 'include')
|
||||
context['PCHInclude'] = PCHInclude
|
||||
context['Template'] = infos.ClassTemplateInfo
|
||||
context['Enum'] = infos.EnumInfo
|
||||
context['AllFromHeader'] = infos.HeaderInfo
|
||||
context['Var'] = infos.VarInfo
|
||||
# functions
|
||||
context['rename'] = infos.rename
|
||||
context['set_policy'] = infos.set_policy
|
||||
context['exclude'] = infos.exclude
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
context['holder'] = infos.holder
|
||||
context['add_method'] = infos.add_method
|
||||
context['final'] = infos.final
|
||||
context['export_values'] = infos.export_values
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
context['return_value_policy'] = return_value_policy
|
||||
context['reference_existing_object'] = reference_existing_object
|
||||
context['copy_const_reference'] = copy_const_reference
|
||||
context['copy_non_const_reference'] = copy_non_const_reference
|
||||
context['return_opaque_pointer'] = return_opaque_pointer
|
||||
context['manage_new_object'] = manage_new_object
|
||||
context['return_by_value'] = return_by_value
|
||||
context['return_self'] = return_self
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')
|
||||
context['module_code'] = lambda code: infos.CodeInfo(code, 'module')
|
||||
context['class_code'] = infos.class_code
|
||||
return context
|
||||
|
||||
|
||||
def Begin():
|
||||
# parse arguments
|
||||
includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main, gccxml_path = ParseArguments()
|
||||
# run pyste scripts
|
||||
for interface in interfaces:
|
||||
ExecuteInterface(interface)
|
||||
# create the parser
|
||||
parser = CppParser(includes, defines, cache_dir, declarations.version, gccxml_path)
|
||||
try:
|
||||
if not create_cache:
|
||||
if not generate_main:
|
||||
return GenerateCode(parser, module, out, interfaces, multiple)
|
||||
else:
|
||||
return GenerateMain(module, out, OrderInterfaces(interfaces))
|
||||
else:
|
||||
return CreateCaches(parser)
|
||||
finally:
|
||||
parser.Close()
|
||||
|
||||
|
||||
def CreateCaches(parser):
|
||||
# There is one cache file per interface so we organize the headers
|
||||
# by interfaces. For each interface collect the tails from the
|
||||
# exporters sharing the same header.
|
||||
tails = JoinTails(exporters.exporters)
|
||||
|
||||
# now for each interface file take each header, and using the tail
|
||||
# get the declarations and cache them.
|
||||
for interface, header in tails:
|
||||
tail = tails[(interface, header)]
|
||||
declarations = parser.ParseWithGCCXML(header, tail)
|
||||
cachefile = parser.CreateCache(header, interface, tail, declarations)
|
||||
print 'Cached', cachefile
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
_imported_count = {} # interface => count
|
||||
|
||||
def ExecuteInterface(interface):
|
||||
old_interface = exporters.current_interface
|
||||
if not os.path.exists(interface):
|
||||
if old_interface and os.path.exists(old_interface):
|
||||
d = os.path.dirname(old_interface)
|
||||
interface = os.path.join(d, interface)
|
||||
if not os.path.exists(interface):
|
||||
raise IOError, "Cannot find interface file %s."%interface
|
||||
|
||||
_imported_count[interface] = _imported_count.get(interface, 0) + 1
|
||||
exporters.current_interface = interface
|
||||
context = CreateContext()
|
||||
context['INTERFACE_FILE'] = os.path.abspath(interface)
|
||||
execfile(interface, context)
|
||||
exporters.current_interface = old_interface
|
||||
|
||||
|
||||
def Import(interface):
|
||||
exporters.importing = True
|
||||
ExecuteInterface(interface)
|
||||
exporters.importing = False
|
||||
|
||||
|
||||
def JoinTails(exports):
|
||||
'''Returns a dict of {(interface, header): tail}, where tail is the
|
||||
joining of all tails of all exports for the header.
|
||||
'''
|
||||
tails = {}
|
||||
for export in exports:
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
tail = export.Tail() or ''
|
||||
if (interface, header) in tails:
|
||||
all_tails = tails[(interface,header)]
|
||||
all_tails += '\n' + tail
|
||||
tails[(interface, header)] = all_tails
|
||||
else:
|
||||
tails[(interface, header)] = tail
|
||||
|
||||
return tails
|
||||
|
||||
|
||||
|
||||
def OrderInterfaces(interfaces):
|
||||
interfaces_order = [(_imported_count[x], x) for x in interfaces]
|
||||
interfaces_order.sort()
|
||||
interfaces_order.reverse()
|
||||
return [x for _, x in interfaces_order]
|
||||
|
||||
|
||||
|
||||
def GenerateMain(module, out, interfaces):
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
codeunit.GenerateMain(interfaces)
|
||||
return 0
|
||||
|
||||
|
||||
def GenerateCode(parser, module, out, interfaces, multiple):
|
||||
# prepare to generate the wrapper code
|
||||
if multiple:
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
else:
|
||||
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
|
||||
# stop referencing the exporters here
|
||||
exports = exporters.exporters
|
||||
exporters.exporters = None
|
||||
exported_names = dict([(x.Name(), None) for x in exports])
|
||||
|
||||
# order the exports
|
||||
order = {}
|
||||
for export in exports:
|
||||
if export.interface_file in order:
|
||||
order[export.interface_file].append(export)
|
||||
else:
|
||||
order[export.interface_file] = [export]
|
||||
exports = []
|
||||
interfaces_order = OrderInterfaces(interfaces)
|
||||
for interface in interfaces_order:
|
||||
exports.extend(order[interface])
|
||||
del order
|
||||
del interfaces_order
|
||||
|
||||
# now generate the code in the correct order
|
||||
#print exported_names
|
||||
tails = JoinTails(exports)
|
||||
for i in xrange(len(exports)):
|
||||
export = exports[i]
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
if header:
|
||||
tail = tails[(interface, header)]
|
||||
declarations, parsed_header = parser.Parse(header, interface, tail)
|
||||
else:
|
||||
declarations = []
|
||||
parsed_header = None
|
||||
ExpandTypedefs(declarations, exported_names)
|
||||
export.SetDeclarations(declarations)
|
||||
export.SetParsedHeader(parsed_header)
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.interface_file, export.Name())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
# force collect of cyclic references
|
||||
exports[i] = None
|
||||
del declarations
|
||||
del export
|
||||
gc.collect()
|
||||
# finally save the code unit
|
||||
codeunit.Save()
|
||||
if not multiple:
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def ExpandTypedefs(decls, exported_names):
|
||||
'''Check if the names in exported_names are a typedef, and add the real class
|
||||
name in the dict.
|
||||
'''
|
||||
for name in exported_names.keys():
|
||||
for decl in decls:
|
||||
if isinstance(decl, declarations.Typedef):
|
||||
exported_names[decl.type.FullName()] = None
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if possible'
|
||||
try:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
except: pass
|
||||
|
||||
|
||||
def main():
|
||||
start = time.clock()
|
||||
UsePsyco()
|
||||
status = Begin()
|
||||
print '%0.2f seconds' % (time.clock()-start)
|
||||
sys.exit(status)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,21 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Global information
|
||||
#==============================================================================
|
||||
|
||||
DEBUG = False
|
||||
USING_BOOST_NS = True
|
||||
|
||||
class namespaces:
|
||||
boost = 'boost::'
|
||||
pyste = ''
|
||||
python = '' # default is to not use boost::python namespace explicitly, so
|
||||
# use the "using namespace" statement instead
|
||||
|
||||
import sys
|
||||
msvc = sys.platform == 'win32'
|
||||
@@ -1,78 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from __future__ import generators
|
||||
import string
|
||||
import sys
|
||||
|
||||
#==============================================================================
|
||||
# enumerate
|
||||
#==============================================================================
|
||||
def enumerate(seq):
|
||||
i = 0
|
||||
for x in seq:
|
||||
yield i, x
|
||||
i += 1
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# makeid
|
||||
#==============================================================================
|
||||
_valid_chars = string.ascii_letters + string.digits + '_'
|
||||
_valid_chars = dict(zip(_valid_chars, _valid_chars))
|
||||
|
||||
def makeid(name):
|
||||
'Returns the name as a valid identifier'
|
||||
if type(name) != str:
|
||||
print type(name), name
|
||||
newname = []
|
||||
for char in name:
|
||||
if char not in _valid_chars:
|
||||
char = '_'
|
||||
newname.append(char)
|
||||
newname = ''.join(newname)
|
||||
# avoid duplications of '_' chars
|
||||
names = [x for x in newname.split('_') if x]
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# remove_duplicated_lines
|
||||
#==============================================================================
|
||||
def remove_duplicated_lines(text):
|
||||
includes = text.splitlines()
|
||||
d = dict([(include, 0) for include in includes])
|
||||
includes = d.keys()
|
||||
includes.sort()
|
||||
return '\n'.join(includes)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# left_equals
|
||||
#==============================================================================
|
||||
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
|
||||
@@ -1,341 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
import unittest
|
||||
import tempfile
|
||||
import os.path
|
||||
from Pyste import GCCXMLParser
|
||||
from Pyste.declarations import *
|
||||
|
||||
|
||||
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)
|
||||
|
||||
def TestDefaultConstructor(self, class_, method, visib):
|
||||
self.TestConstructor(class_, method, visib)
|
||||
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.TestType(
|
||||
param,
|
||||
ReferenceType,
|
||||
class_.FullName(),
|
||||
'const %s&' % class_.FullName(),
|
||||
True)
|
||||
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)
|
||||
|
||||
|
||||
class ClassBaseTest(Tester):
|
||||
|
||||
def setUp(self):
|
||||
self.base = GetDecl('Base')
|
||||
|
||||
def testClass(self):
|
||||
'test the properties of the class Base'
|
||||
self.assert_(isinstance(self.base, Class))
|
||||
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.TestType(param, FundamentalType, 'int', 'int', False)
|
||||
self.assertEqual(foo.namespace, None)
|
||||
self.assertEqual(
|
||||
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)
|
||||
|
||||
def testConstructors(self):
|
||||
'test constructors in class Base'
|
||||
constructors = GetMembers(self.base, 'Base')
|
||||
for cons in constructors:
|
||||
if len(cons.parameters) == 0:
|
||||
self.TestDefaultConstructor(self.base, cons, Scope.public)
|
||||
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
|
||||
self.TestType(intp, FundamentalType, 'int', 'int', False)
|
||||
self.TestType(floatp, FundamentalType, 'float', 'float', False)
|
||||
|
||||
def testSimple(self):
|
||||
'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.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)
|
||||
|
||||
|
||||
class ClassTemplateTest(Tester):
|
||||
|
||||
def setUp(self):
|
||||
self.template = GetDecl('Template<int>')
|
||||
|
||||
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>')
|
||||
|
||||
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:
|
||||
self.TestDefaultConstructor(self.template, cons, Scope.public)
|
||||
elif len(cons.parameters) == 1:
|
||||
self.TestCopyConstructor(self.template, cons, Scope.public)
|
||||
|
||||
|
||||
def testValue(self):
|
||||
'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')
|
||||
|
||||
def testBase(self):
|
||||
'test the superclasses of Template<int>'
|
||||
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)
|
||||
|
||||
|
||||
|
||||
class FreeFuncTest(Tester):
|
||||
|
||||
def setUp(self):
|
||||
self.func = GetDecl('FreeFunc')
|
||||
|
||||
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.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)
|
||||
|
||||
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.TestType(intp, FundamentalType, 'int', 'int', False)
|
||||
self.assertEqual(intp.default, '10')
|
||||
|
||||
|
||||
|
||||
class testFunctionPointers(Tester):
|
||||
|
||||
def testMethodPointer(self):
|
||||
'test declaration of a pointer-to-method'
|
||||
meth = GetDecl('MethodTester')
|
||||
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]
|
||||
fullname = 'void (*)(int)'
|
||||
self.TestType(param, PointerType, fullname, fullname, False)
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Support routines
|
||||
# =============================================================================
|
||||
|
||||
cppcode = '''
|
||||
namespace std {
|
||||
class string;
|
||||
}
|
||||
namespace test {
|
||||
class Base
|
||||
{
|
||||
public:
|
||||
Base();
|
||||
Base(const Base&);
|
||||
Base(int, float);
|
||||
|
||||
virtual void foo(int = 0.0) = 0;
|
||||
static int z;
|
||||
protected:
|
||||
bool simple(const std::string&);
|
||||
private:
|
||||
int x;
|
||||
};
|
||||
|
||||
void MethodTester( void (Base::*)(int) );
|
||||
void FunctionTester( void (*)(int) );
|
||||
|
||||
|
||||
const Base & FreeFunc(const std::string&, int=10);
|
||||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct Template: protected test::Base
|
||||
{
|
||||
T value;
|
||||
virtual void foo(int);
|
||||
};
|
||||
|
||||
Template<int> __aTemplateInt;
|
||||
'''
|
||||
|
||||
def GetXMLFile():
|
||||
'''Generates an gccxml file using the code from the global cppcode.
|
||||
Returns the xml's filename.'''
|
||||
# write the code to a header file
|
||||
tmpfile = tempfile.mktemp() + '.h'
|
||||
f = file(tmpfile, 'w')
|
||||
f.write(cppcode)
|
||||
f.close()
|
||||
# run gccxml
|
||||
outfile = tmpfile + '.xml'
|
||||
if os.system('gccxml "%s" "-fxml=%s"' % (tmpfile, outfile)) != 0:
|
||||
raise RuntimeError, 'Error executing GCCXML.'
|
||||
# read the output file into the xmlcode
|
||||
f = file(outfile)
|
||||
xmlcode = f.read()
|
||||
#print xmlcode
|
||||
f.close()
|
||||
# remove the header
|
||||
os.remove(tmpfile)
|
||||
return outfile
|
||||
|
||||
|
||||
|
||||
def GetDeclarations():
|
||||
'Uses the GCCXMLParser module to get the declarations.'
|
||||
xmlfile = GetXMLFile()
|
||||
declarations = GCCXMLParser.ParseDeclarations(xmlfile)
|
||||
os.remove(xmlfile)
|
||||
return declarations
|
||||
|
||||
# the declarations to be analysed
|
||||
declarations = GetDeclarations()
|
||||
|
||||
|
||||
def GetDecl(name):
|
||||
'returns one of the top declarations given its name'
|
||||
for decl in declarations:
|
||||
if decl.name == name:
|
||||
return decl
|
||||
else:
|
||||
raise RuntimeError, 'Declaration not found: %s' % name
|
||||
|
||||
|
||||
def GetMember(class_, name):
|
||||
'gets the member of the given class by its name'
|
||||
|
||||
res = None
|
||||
multipleFound = False
|
||||
for member in class_:
|
||||
if member.name == name:
|
||||
if res is not None:
|
||||
multipleFound = True
|
||||
break
|
||||
res = member
|
||||
if res is None or multipleFound:
|
||||
raise RuntimeError, \
|
||||
'No member or more than one member found in class %s: %s' \
|
||||
% (class_.name, name)
|
||||
return res
|
||||
|
||||
|
||||
def GetMembers(class_, name):
|
||||
'gets the members of the given class by its name'
|
||||
res = []
|
||||
for member in class_:
|
||||
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)
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,84 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
from SmartFile import *
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
class SmartFileTest(unittest.TestCase):
|
||||
|
||||
FILENAME = tempfile.mktemp()
|
||||
|
||||
def setUp(self):
|
||||
self._Clean()
|
||||
|
||||
def tearDown(self):
|
||||
self._Clean()
|
||||
|
||||
def _Clean(self):
|
||||
try:
|
||||
os.remove(self.FILENAME)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def testNonExistant(self):
|
||||
"Must override the file, as there's no file in the disk yet"
|
||||
self.assert_(not os.path.isfile(self.FILENAME))
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write('Testing 123\nTesting again.')
|
||||
f.close()
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
|
||||
|
||||
def testOverride(self):
|
||||
"Must override the file, because the contents are different"
|
||||
contents = 'Contents!\nContents!'
|
||||
# create the file normally first
|
||||
f = file(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
time.sleep(2)
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write(contents + '_')
|
||||
f.close()
|
||||
new_file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(new_file_time != file_time)
|
||||
|
||||
|
||||
def testNoOverride(self):
|
||||
"Must not override the file, because the contents are the same"
|
||||
contents = 'Contents!\nContents!'
|
||||
# create the file normally first
|
||||
f = file(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
time.sleep(2)
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
new_file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(new_file_time == file_time)
|
||||
|
||||
|
||||
def testAutoClose(self):
|
||||
"Must be closed when garbage-collected"
|
||||
def foo():
|
||||
f = SmartFile(self.FILENAME)
|
||||
f.write('testing')
|
||||
self.assert_(not os.path.isfile(self.FILENAME))
|
||||
foo()
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,22 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace abstract {
|
||||
|
||||
struct A {
|
||||
virtual ~A() {}
|
||||
virtual std::string f()=0;
|
||||
};
|
||||
|
||||
struct B: A {
|
||||
std::string f() { return "B::f"; }
|
||||
};
|
||||
|
||||
std::string call(A* a) { return a->f(); }
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Class('abstract::A', 'abstract_test.h')
|
||||
Class('abstract::B', 'abstract_test.h')
|
||||
Function('abstract::call', 'abstract_test.h')
|
||||
@@ -1,26 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _abstract_test import *
|
||||
|
||||
class AbstractTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
class C(A):
|
||||
def f(self):
|
||||
return 'C::f'
|
||||
|
||||
a = A()
|
||||
b = B()
|
||||
c = C()
|
||||
self.assertRaises(RuntimeError, a.f)
|
||||
self.assertEqual(b.f(), 'B::f')
|
||||
self.assertEqual(call(b), 'B::f')
|
||||
self.assertEqual(c.f(), 'C::f')
|
||||
self.assertEqual(call(c), 'C::f')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,18 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
namespace add_test {
|
||||
|
||||
struct C
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
const int get_x(C& c)
|
||||
{
|
||||
return c.x;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
C = Class('add_test::C', 'add_test.h')
|
||||
add_method(C, 'add_test::get_x')
|
||||
@@ -1,16 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _add_test import *
|
||||
|
||||
class AddMethodTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
c = C()
|
||||
c.x = 10
|
||||
self.assertEqual(c.get_x(), 10)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,13 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include "basic.h"
|
||||
|
||||
namespace basic {
|
||||
|
||||
int C::static_value = 3;
|
||||
const int C::const_static_value = 100;
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef BASIC_H
|
||||
#define BASIC_H
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace basic {
|
||||
|
||||
struct C
|
||||
{
|
||||
// test virtuallity
|
||||
C(): value(1), const_value(0) {}
|
||||
virtual int f(int x = 10)
|
||||
{
|
||||
return x*2;
|
||||
}
|
||||
|
||||
int foo(int x=1){
|
||||
return x+1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
int value;
|
||||
const int const_value;
|
||||
|
||||
// test static functions
|
||||
static int mul(int x, int y) { return x*y; }
|
||||
static double mul(double x, double y) { return x*y; }
|
||||
|
||||
static int square(int x=2) { return x*x; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c)
|
||||
{
|
||||
return c.f();
|
||||
}
|
||||
|
||||
inline int call_f(C& c, int x)
|
||||
{
|
||||
return c.f(x);
|
||||
}
|
||||
|
||||
inline int get_static()
|
||||
{
|
||||
return C::static_value;
|
||||
}
|
||||
|
||||
inline int get_value(C& c)
|
||||
{
|
||||
return c.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +0,0 @@
|
||||
Class('basic::C', 'basic.h')
|
||||
Function('basic::call_f', 'basic.h')
|
||||
Function('basic::get_static', 'basic.h')
|
||||
Function('basic::get_value', 'basic.h')
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _basic import *
|
||||
|
||||
class BasicExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
|
||||
# test virtual functions
|
||||
class D(C):
|
||||
def f(self, x=10):
|
||||
return x+1
|
||||
|
||||
d = D()
|
||||
c = C()
|
||||
|
||||
self.assertEqual(c.f(), 20)
|
||||
self.assertEqual(c.f(3), 6)
|
||||
self.assertEqual(d.f(), 11)
|
||||
self.assertEqual(d.f(3), 4)
|
||||
self.assertEqual(call_f(c), 20)
|
||||
self.assertEqual(call_f(c, 4), 8)
|
||||
self.assertEqual(call_f(d), 11)
|
||||
self.assertEqual(call_f(d, 3), 4)
|
||||
|
||||
# test data members
|
||||
def testValue(value):
|
||||
self.assertEqual(c.value, value)
|
||||
self.assertEqual(d.value, value)
|
||||
self.assertEqual(get_value(c), value)
|
||||
self.assertEqual(get_value(d), value)
|
||||
testValue(1)
|
||||
c.value = 30
|
||||
d.value = 30
|
||||
testValue(30)
|
||||
self.assertEqual(c.const_value, 0)
|
||||
self.assertEqual(d.const_value, 0)
|
||||
def set_const_value():
|
||||
c.const_value = 12
|
||||
self.assertRaises(AttributeError, set_const_value)
|
||||
|
||||
# test static data-members
|
||||
def testStatic(value):
|
||||
self.assertEqual(C.static_value, value)
|
||||
self.assertEqual(c.static_value, value)
|
||||
self.assertEqual(D.static_value, value)
|
||||
self.assertEqual(d.static_value, value)
|
||||
self.assertEqual(get_static(), value)
|
||||
testStatic(3)
|
||||
C.static_value = 10
|
||||
testStatic(10)
|
||||
self.assertEqual(C.const_static_value, 100)
|
||||
def set_const_static():
|
||||
C.const_static_value = 1
|
||||
self.assertRaises(AttributeError, set_const_static)
|
||||
|
||||
# test static function
|
||||
def test_mul(result, *args):
|
||||
self.assertEqual(C.mul(*args), result)
|
||||
self.assertEqual(c.mul(*args), result)
|
||||
test_mul(16, 8, 2)
|
||||
test_mul(6.0, 2.0, 3.0)
|
||||
self.assertEqual(C.square(), 4)
|
||||
self.assertEqual(c.square(), 4)
|
||||
self.assertEqual(C.square(3), 9)
|
||||
self.assertEqual(c.square(3), 9)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
struct A {
|
||||
int x;
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
Class('A', 'code_test.h')
|
||||
Include('string')
|
||||
declaration_code('''
|
||||
int get(A& a) { return a.x; }
|
||||
|
||||
std::string foo() { return "Hello!"; }
|
||||
''')
|
||||
module_code(' def("get", &get);\n')
|
||||
module_code(' def("foo", &foo);\n')
|
||||
@@ -1,18 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _code_test import *
|
||||
|
||||
class CodeTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A()
|
||||
a.x = 12
|
||||
self.assertEqual(get(a), 12)
|
||||
self.assertEqual(foo(), "Hello!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,34 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef ENUMS_H
|
||||
#define ENUMS_H
|
||||
|
||||
namespace enums {
|
||||
|
||||
enum color { red, blue };
|
||||
|
||||
struct X
|
||||
{
|
||||
enum choices
|
||||
{
|
||||
good = 1,
|
||||
bad = 2
|
||||
};
|
||||
|
||||
int set(choices c)
|
||||
{
|
||||
return (int)c;
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
x = 0,
|
||||
y = 1
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
h = AllFromHeader('enums.h')
|
||||
rename(h.color.red, 'Red')
|
||||
rename(h.color.blue, 'Blue')
|
||||
export_values(h.color)
|
||||
rename(h.X.choices.bad, 'Bad')
|
||||
rename(h.X.choices.good, 'Good')
|
||||
rename(h.X.choices, 'Choices')
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _enums import *
|
||||
|
||||
class EnumsTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(int(Red), 0)
|
||||
self.assertEqual(int(Blue), 1)
|
||||
|
||||
self.assertEqual(int(X.Choices.Good), 1)
|
||||
self.assertEqual(int(X.Choices.Bad), 2)
|
||||
a = X()
|
||||
self.assertEqual(a.set(a.Choices.Good), 1)
|
||||
self.assertEqual(a.set(a.Choices.Bad), 2)
|
||||
self.assertEqual(x, 0)
|
||||
self.assertEqual(y, 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef HEADER_TEST_H
|
||||
#define HEADER_TEST_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace header_test {
|
||||
|
||||
enum choice { red, blue };
|
||||
|
||||
inline std::string choice_str(choice c)
|
||||
{
|
||||
std::map<choice, std::string> choice_map;
|
||||
choice_map[red] = "red";
|
||||
choice_map[blue] = "blue";
|
||||
return choice_map[c];
|
||||
}
|
||||
|
||||
struct C
|
||||
{
|
||||
choice c;
|
||||
|
||||
std::string get()
|
||||
{
|
||||
return choice_str(c);
|
||||
}
|
||||
};
|
||||
|
||||
// test the exclusion of the following
|
||||
|
||||
struct ForwardDeclared; // should be excluded automatically
|
||||
struct A {};
|
||||
void foo();
|
||||
enum bar { value };
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +0,0 @@
|
||||
h = AllFromHeader('header_test.h')
|
||||
exclude(h.A)
|
||||
exclude(h.foo)
|
||||
exclude(h.bar)
|
||||
@@ -1,27 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _header_test import *
|
||||
|
||||
class HeaderTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(choice.red, 0)
|
||||
self.assertEqual(choice.blue, 1)
|
||||
self.assertEqual(choice_str(choice.blue), 'blue')
|
||||
self.assertEqual(choice_str(choice.red), 'red')
|
||||
c = C()
|
||||
c.c = choice.blue
|
||||
self.assertEqual(c.get(), 'blue')
|
||||
c.c = choice.red
|
||||
self.assertEqual(c.get(), 'red')
|
||||
# the following classes/functions should not have being exported
|
||||
self.assertRaises(NameError, lambda: A())
|
||||
self.assertRaises(NameError, lambda: foo())
|
||||
self.assertRaises(NameError, lambda: bar.value)
|
||||
self.assertRaises(NameError, lambda: ForwardDeclared())
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,55 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import sys
|
||||
from Pyste.infos import *
|
||||
from Pyste.policies import *
|
||||
from Pyste.exporterutils import *
|
||||
import unittest
|
||||
|
||||
#================================================================================
|
||||
# InfosTest
|
||||
#================================================================================
|
||||
class InfosTest(unittest.TestCase):
|
||||
|
||||
def testFunctionInfo(self):
|
||||
info = FunctionInfo('test::foo', 'foo.h')
|
||||
rename(info, 'hello')
|
||||
set_policy(info, return_internal_reference())
|
||||
set_wrapper(info, FunctionWrapper('foo_wrapper'))
|
||||
|
||||
info = InfoWrapper(info)
|
||||
|
||||
self.assertEqual(info.rename, 'hello')
|
||||
self.assertEqual(info.policy.Code(), 'return_internal_reference< 1 >')
|
||||
self.assertEqual(info.wrapper.name, 'foo_wrapper')
|
||||
|
||||
|
||||
def testClassInfo(self):
|
||||
info = ClassInfo('test::IFoo', 'foo.h')
|
||||
rename(info.name, 'Name')
|
||||
rename(info.exclude, 'Exclude')
|
||||
rename(info, 'Foo')
|
||||
rename(info.Bar, 'bar')
|
||||
set_policy(info.Baz, return_internal_reference())
|
||||
rename(info.operator['>>'], 'from_string')
|
||||
exclude(info.Bar)
|
||||
set_wrapper(info.Baz, FunctionWrapper('baz_wrapper'))
|
||||
|
||||
info = InfoWrapper(info)
|
||||
|
||||
self.assertEqual(info.rename, 'Foo')
|
||||
self.assertEqual(info['Bar'].rename, 'bar')
|
||||
self.assertEqual(info['name'].rename, 'Name')
|
||||
self.assertEqual(info['exclude'].rename, 'Exclude')
|
||||
self.assertEqual(info['Bar'].exclude, True)
|
||||
self.assertEqual(info['Baz'].policy.Code(), 'return_internal_reference< 1 >')
|
||||
self.assertEqual(info['Baz'].wrapper.name, 'baz_wrapper')
|
||||
self.assertEqual(info['operator']['>>'].rename, 'from_string')
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include "inherit.h"
|
||||
|
||||
int inherit::C::s = 1;
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
namespace inherit {
|
||||
|
||||
template<typename T>
|
||||
class A
|
||||
{
|
||||
public:
|
||||
void set(T v) { mData = v; }
|
||||
|
||||
T get() const { return mData; }
|
||||
|
||||
private:
|
||||
T mData;
|
||||
};
|
||||
|
||||
|
||||
class B : public A<int>
|
||||
{
|
||||
public:
|
||||
int go() { return get(); }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
{
|
||||
enum ab { a = 1, b = 2 };
|
||||
int f1() { return 1; }
|
||||
int x;
|
||||
static int s;
|
||||
};
|
||||
|
||||
struct D : C
|
||||
{
|
||||
int f2() { return 2; }
|
||||
int y;
|
||||
};
|
||||
|
||||
struct X {};
|
||||
struct E: X, D {};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
A = Template('inherit::A', 'inherit.h')
|
||||
A_int = A('int', 'A_int')
|
||||
|
||||
Class('inherit::B', 'inherit.h')
|
||||
Class('inherit::D', 'inherit.h')
|
||||
E = Class('inherit::E', 'inherit.h')
|
||||
exclude(E.s)
|
||||
exclude(E.ab)
|
||||
@@ -1,35 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
namespace inherit2 {
|
||||
|
||||
struct A
|
||||
{
|
||||
int x;
|
||||
int getx() { return x; }
|
||||
int foo() { return 0; }
|
||||
int foo(int x) { return x; }
|
||||
};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
int y;
|
||||
int gety() { return y; }
|
||||
int foo() { return 1; }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
{
|
||||
int z;
|
||||
int getz() { return z; }
|
||||
};
|
||||
|
||||
struct D : C
|
||||
{
|
||||
int w;
|
||||
int getw() { return w; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
Class('inherit2::B', 'inherit2.h')
|
||||
Class('inherit2::D', 'inherit2.h')
|
||||
@@ -1,31 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _inherit2 import *
|
||||
|
||||
class InheritExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
b = B()
|
||||
d = D()
|
||||
|
||||
self.assert_(issubclass(D, B))
|
||||
b.x, b.y = 10, 5
|
||||
self.assertEqual(b.getx(), 10)
|
||||
self.assertEqual(b.gety(), 5)
|
||||
d.x, d.y, d.z, d.w = 20, 15, 10, 5
|
||||
self.assertEqual(d.getx(), 20)
|
||||
self.assertEqual(d.gety(), 15)
|
||||
self.assertEqual(d.getz(), 10)
|
||||
self.assertEqual(d.getw(), 5)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(b.foo(3), 3)
|
||||
|
||||
def wrong():
|
||||
return b.getw()
|
||||
self.assertRaises(AttributeError, wrong)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,46 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
namespace inherit3 {
|
||||
|
||||
struct A
|
||||
{
|
||||
A() { x = 0; }
|
||||
struct X { int y; };
|
||||
int x;
|
||||
virtual int foo() { return 0; }
|
||||
virtual int foo(int x) { return x; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
B() { x = 0; }
|
||||
struct X { int y; };
|
||||
int x;
|
||||
int foo() { return 1; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct C: A
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
Class('inherit3::B', 'inherit3.h')
|
||||
Class('inherit3::C', 'inherit3.h')
|
||||
@@ -1,27 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _inherit3 import *
|
||||
|
||||
class testInherit3(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
def testInst(c):
|
||||
self.assertEqual(c.x, 0)
|
||||
self.assertEqual(c.foo(3), 3)
|
||||
x = c.X()
|
||||
self.assertEqual(x.y, 0)
|
||||
self.assertEqual(c.E.i, 0)
|
||||
self.assertEqual(c.E.j, 1)
|
||||
b = B()
|
||||
c = C()
|
||||
testInst(b)
|
||||
testInst(c)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(c.foo(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,23 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
namespace inherit4 {
|
||||
|
||||
struct A
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
int y;
|
||||
};
|
||||
|
||||
struct C: B
|
||||
{
|
||||
int z;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Class('inherit4::A', 'inherit4.h')
|
||||
Class('inherit4::B', 'inherit4.h')
|
||||
Class('inherit4::C', 'inherit4.h')
|
||||
@@ -1,31 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _inherit4 import *
|
||||
|
||||
class TestInherit4(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assert_(issubclass(B, A))
|
||||
self.assert_(issubclass(C, A))
|
||||
self.assert_(issubclass(C, B))
|
||||
a = A()
|
||||
a.x = 1
|
||||
b = B()
|
||||
b.x = 10
|
||||
b.y = 20
|
||||
c = C()
|
||||
c.x = 100
|
||||
c.y = 200
|
||||
c.z = 300
|
||||
self.assertEqual(a.x, 1)
|
||||
self.assertEqual(b.x, 10)
|
||||
self.assertEqual(b.y, 20)
|
||||
self.assertEqual(c.x, 100)
|
||||
self.assertEqual(c.y, 200)
|
||||
self.assertEqual(c.z, 300)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,33 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _inherit import *
|
||||
|
||||
class InheritExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A_int()
|
||||
b = B()
|
||||
self.assert_(isinstance(b, A_int))
|
||||
self.assert_(issubclass(B, A_int))
|
||||
a.set(10)
|
||||
self.assertEqual(a.get(), 10)
|
||||
b.set(1)
|
||||
self.assertEqual(b.go(), 1)
|
||||
self.assertEqual(b.get(), 1)
|
||||
|
||||
d = D()
|
||||
self.assert_(issubclass(D, B))
|
||||
self.assertEqual(d.x, 0)
|
||||
self.assertEqual(d.y, 0)
|
||||
self.assertEqual(d.s, 1)
|
||||
self.assertEqual(D.s, 1)
|
||||
self.assertEqual(d.f1(), 1)
|
||||
self.assertEqual(d.f2(), 2)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,9 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include "nested.h"
|
||||
|
||||
int nested::X::staticXValue = 10;
|
||||
int nested::X::Y::staticYValue = 20;
|
||||
@@ -1,32 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#ifndef NESTED_H
|
||||
#define NESTED_H
|
||||
|
||||
namespace nested {
|
||||
|
||||
struct X
|
||||
{
|
||||
struct Y
|
||||
{
|
||||
int valueY;
|
||||
static int staticYValue;
|
||||
struct Z
|
||||
{
|
||||
int valueZ;
|
||||
};
|
||||
};
|
||||
|
||||
static int staticXValue;
|
||||
int valueX;
|
||||
};
|
||||
|
||||
typedef X Root;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
Class('nested::Root', 'nested.h')
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
# distribution is subject to the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
import unittest
|
||||
from _nested import *
|
||||
|
||||
class NestedTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(Root.staticXValue, 10)
|
||||
self.assertEqual(Root.Y.staticYValue, 20)
|
||||
z = Root.Y.Z()
|
||||
z.valueZ = 3
|
||||
self.assertEqual(z.valueZ, 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,57 +0,0 @@
|
||||
/* Copyright Bruno da Silva de Oliveira 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef OPAQUE_H
|
||||
#define OPAQUE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace opaque {
|
||||
|
||||
|
||||
struct C {
|
||||
C(int v): value(v) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
inline C* new_C()
|
||||
{
|
||||
return new C(10);
|
||||
}
|
||||
|
||||
inline C* new_C_zero()
|
||||
{
|
||||
return new C(0);
|
||||
}
|
||||
|
||||
inline int get(C* c)
|
||||
{
|
||||
return c->value;
|
||||
}
|
||||
|
||||
struct D {
|
||||
D(double v): value(v) {}
|
||||
double value;
|
||||
};
|
||||
|
||||
struct A
|
||||
{
|
||||
D* new_handle()
|
||||
{
|
||||
return new D(3.0);
|
||||
}
|
||||
|
||||
double get(D* d)
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
int f(int x=0) { return x; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
foo = Function('opaque::new_C', 'opaque.h')
|
||||
set_policy(foo, return_value_policy(return_opaque_pointer))
|
||||
foo = Function('opaque::new_C_zero', 'opaque.h')
|
||||
set_policy(foo, return_value_policy(return_opaque_pointer))
|
||||
Function('opaque::get', 'opaque.h' )
|
||||
A = Class('opaque::A', 'opaque.h')
|
||||
set_policy(A.new_handle, return_value_policy(return_opaque_pointer))
|
||||