diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-06-25 22:59:01 +0000 |
---|---|---|
committer | <> | 2013-09-27 11:49:28 +0000 |
commit | 8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch) | |
tree | c09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/python/pyste | |
download | boost-tarball-baserock/morph.tar.gz |
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/python/pyste')
126 files changed, 8668 insertions, 0 deletions
diff --git a/libs/python/pyste/NEWS b/libs/python/pyste/NEWS new file mode 100644 index 000000000..31a5ceba2 --- /dev/null +++ b/libs/python/pyste/NEWS @@ -0,0 +1,212 @@ +.. 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. diff --git a/libs/python/pyste/README b/libs/python/pyste/README new file mode 100644 index 000000000..c378f3916 --- /dev/null +++ b/libs/python/pyste/README @@ -0,0 +1,35 @@ +.. 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). diff --git a/libs/python/pyste/TODO b/libs/python/pyste/TODO new file mode 100644 index 000000000..0b3c9024f --- /dev/null +++ b/libs/python/pyste/TODO @@ -0,0 +1,18 @@ +.. 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 diff --git a/libs/python/pyste/dist/create_build.py b/libs/python/pyste/dist/create_build.py new file mode 100644 index 000000000..a68369951 --- /dev/null +++ b/libs/python/pyste/dist/create_build.py @@ -0,0 +1,55 @@ +# 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() diff --git a/libs/python/pyste/dist/setup.py b/libs/python/pyste/dist/setup.py new file mode 100644 index 000000000..fc7c74e21 --- /dev/null +++ b/libs/python/pyste/dist/setup.py @@ -0,0 +1,10 @@ +# 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']) diff --git a/libs/python/pyste/doc/adding_new_methods.html b/libs/python/pyste/doc/adding_new_methods.html new file mode 100644 index 000000000..afa772bcc --- /dev/null +++ b/libs/python/pyste/doc/adding_new_methods.html @@ -0,0 +1,79 @@ +<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> diff --git a/libs/python/pyste/doc/exporting_an_entire_header.html b/libs/python/pyste/doc/exporting_an_entire_header.html new file mode 100644 index 000000000..db25325ca --- /dev/null +++ b/libs/python/pyste/doc/exporting_an_entire_header.html @@ -0,0 +1,85 @@ +<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> diff --git a/libs/python/pyste/doc/global_variables.html b/libs/python/pyste/doc/global_variables.html new file mode 100644 index 000000000..0efd2950b --- /dev/null +++ b/libs/python/pyste/doc/global_variables.html @@ -0,0 +1,49 @@ +<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> diff --git a/libs/python/pyste/doc/inserting_code.html b/libs/python/pyste/doc/inserting_code.html new file mode 100644 index 000000000..97eb70f38 --- /dev/null +++ b/libs/python/pyste/doc/inserting_code.html @@ -0,0 +1,72 @@ +<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> diff --git a/libs/python/pyste/doc/introduction.html b/libs/python/pyste/doc/introduction.html new file mode 100644 index 000000000..943884931 --- /dev/null +++ b/libs/python/pyste/doc/introduction.html @@ -0,0 +1,73 @@ +<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> diff --git a/libs/python/pyste/doc/policies.html b/libs/python/pyste/doc/policies.html new file mode 100644 index 000000000..3628093bd --- /dev/null +++ b/libs/python/pyste/doc/policies.html @@ -0,0 +1,90 @@ +<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> diff --git a/libs/python/pyste/doc/pyste.txt b/libs/python/pyste/doc/pyste.txt new file mode 100644 index 000000000..186a31cba --- /dev/null +++ b/libs/python/pyste/doc/pyste.txt @@ -0,0 +1,664 @@ +[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 */ + } diff --git a/libs/python/pyste/doc/renaming_and_excluding.html b/libs/python/pyste/doc/renaming_and_excluding.html new file mode 100644 index 000000000..ce6654c4a --- /dev/null +++ b/libs/python/pyste/doc/renaming_and_excluding.html @@ -0,0 +1,87 @@ +<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> diff --git a/libs/python/pyste/doc/running_pyste.html b/libs/python/pyste/doc/running_pyste.html new file mode 100644 index 000000000..9bd9a3aee --- /dev/null +++ b/libs/python/pyste/doc/running_pyste.html @@ -0,0 +1,200 @@ +<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> diff --git a/libs/python/pyste/doc/smart_pointers.html b/libs/python/pyste/doc/smart_pointers.html new file mode 100644 index 000000000..cddc96f2f --- /dev/null +++ b/libs/python/pyste/doc/smart_pointers.html @@ -0,0 +1,84 @@ +<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> diff --git a/libs/python/pyste/doc/templates.html b/libs/python/pyste/doc/templates.html new file mode 100644 index 000000000..a1c1cfefb --- /dev/null +++ b/libs/python/pyste/doc/templates.html @@ -0,0 +1,102 @@ +<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> diff --git a/libs/python/pyste/doc/the_interface_files.html b/libs/python/pyste/doc/the_interface_files.html new file mode 100644 index 000000000..9c0200432 --- /dev/null +++ b/libs/python/pyste/doc/the_interface_files.html @@ -0,0 +1,102 @@ +<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> diff --git a/libs/python/pyste/doc/theme/alert.gif b/libs/python/pyste/doc/theme/alert.gif Binary files differnew file mode 100644 index 000000000..270764cc5 --- /dev/null +++ b/libs/python/pyste/doc/theme/alert.gif diff --git a/libs/python/pyste/doc/theme/arrow.gif b/libs/python/pyste/doc/theme/arrow.gif Binary files differnew file mode 100644 index 000000000..e33db0fb4 --- /dev/null +++ b/libs/python/pyste/doc/theme/arrow.gif diff --git a/libs/python/pyste/doc/theme/bkd.gif b/libs/python/pyste/doc/theme/bkd.gif Binary files differnew file mode 100644 index 000000000..dcabcb806 --- /dev/null +++ b/libs/python/pyste/doc/theme/bkd.gif diff --git a/libs/python/pyste/doc/theme/bkd2.gif b/libs/python/pyste/doc/theme/bkd2.gif Binary files differnew file mode 100644 index 000000000..b03d9ba97 --- /dev/null +++ b/libs/python/pyste/doc/theme/bkd2.gif diff --git a/libs/python/pyste/doc/theme/bulb.gif b/libs/python/pyste/doc/theme/bulb.gif Binary files differnew file mode 100644 index 000000000..74f3baac4 --- /dev/null +++ b/libs/python/pyste/doc/theme/bulb.gif diff --git a/libs/python/pyste/doc/theme/bullet.gif b/libs/python/pyste/doc/theme/bullet.gif Binary files differnew file mode 100644 index 000000000..da787e2ef --- /dev/null +++ b/libs/python/pyste/doc/theme/bullet.gif diff --git a/libs/python/pyste/doc/theme/l_arr.gif b/libs/python/pyste/doc/theme/l_arr.gif Binary files differnew file mode 100644 index 000000000..5b3cb1cbf --- /dev/null +++ b/libs/python/pyste/doc/theme/l_arr.gif diff --git a/libs/python/pyste/doc/theme/l_arr_disabled.gif b/libs/python/pyste/doc/theme/l_arr_disabled.gif Binary files differnew file mode 100644 index 000000000..ed58a605a --- /dev/null +++ b/libs/python/pyste/doc/theme/l_arr_disabled.gif diff --git a/libs/python/pyste/doc/theme/note.gif b/libs/python/pyste/doc/theme/note.gif Binary files differnew file mode 100644 index 000000000..bd92f0755 --- /dev/null +++ b/libs/python/pyste/doc/theme/note.gif diff --git a/libs/python/pyste/doc/theme/r_arr.gif b/libs/python/pyste/doc/theme/r_arr.gif Binary files differnew file mode 100644 index 000000000..2dcdad117 --- /dev/null +++ b/libs/python/pyste/doc/theme/r_arr.gif diff --git a/libs/python/pyste/doc/theme/r_arr_disabled.gif b/libs/python/pyste/doc/theme/r_arr_disabled.gif Binary files differnew file mode 100644 index 000000000..2100f78bf --- /dev/null +++ b/libs/python/pyste/doc/theme/r_arr_disabled.gif diff --git a/libs/python/pyste/doc/theme/smiley.gif b/libs/python/pyste/doc/theme/smiley.gif Binary files differnew file mode 100644 index 000000000..4c848f8fe --- /dev/null +++ b/libs/python/pyste/doc/theme/smiley.gif diff --git a/libs/python/pyste/doc/theme/style.css b/libs/python/pyste/doc/theme/style.css new file mode 100644 index 000000000..643df02a9 --- /dev/null +++ b/libs/python/pyste/doc/theme/style.css @@ -0,0 +1,178 @@ +/*============================================================================= + 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 } diff --git a/libs/python/pyste/doc/theme/u_arr.gif b/libs/python/pyste/doc/theme/u_arr.gif Binary files differnew file mode 100644 index 000000000..ada3d6e04 --- /dev/null +++ b/libs/python/pyste/doc/theme/u_arr.gif diff --git a/libs/python/pyste/doc/wrappers.html b/libs/python/pyste/doc/wrappers.html new file mode 100644 index 000000000..534ae5529 --- /dev/null +++ b/libs/python/pyste/doc/wrappers.html @@ -0,0 +1,124 @@ +<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> diff --git a/libs/python/pyste/index.html b/libs/python/pyste/index.html new file mode 100644 index 000000000..953b37c12 --- /dev/null +++ b/libs/python/pyste/index.html @@ -0,0 +1,90 @@ +<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> diff --git a/libs/python/pyste/install/pyste.py b/libs/python/pyste/install/pyste.py new file mode 100644 index 000000000..da9262353 --- /dev/null +++ b/libs/python/pyste/install/pyste.py @@ -0,0 +1,8 @@ +#!/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() diff --git a/libs/python/pyste/install/setup.py b/libs/python/pyste/install/setup.py new file mode 100644 index 000000000..c17039817 --- /dev/null +++ b/libs/python/pyste/install/setup.py @@ -0,0 +1,20 @@ +# 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'}, + ) diff --git a/libs/python/pyste/src/Pyste/ClassExporter.py b/libs/python/pyste/src/Pyste/ClassExporter.py new file mode 100644 index 000000000..decaf628e --- /dev/null +++ b/libs/python/pyste/src/Pyste/ClassExporter.py @@ -0,0 +1,918 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/CodeExporter.py b/libs/python/pyste/src/Pyste/CodeExporter.py new file mode 100644 index 000000000..382fffbd5 --- /dev/null +++ b/libs/python/pyste/src/Pyste/CodeExporter.py @@ -0,0 +1,26 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/CppParser.py b/libs/python/pyste/src/Pyste/CppParser.py new file mode 100644 index 000000000..be68a448a --- /dev/null +++ b/libs/python/pyste/src/Pyste/CppParser.py @@ -0,0 +1,247 @@ +# 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) diff --git a/libs/python/pyste/src/Pyste/EnumExporter.py b/libs/python/pyste/src/Pyste/EnumExporter.py new file mode 100644 index 000000000..0107fbee3 --- /dev/null +++ b/libs/python/pyste/src/Pyste/EnumExporter.py @@ -0,0 +1,58 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/Exporter.py b/libs/python/pyste/src/Pyste/Exporter.py new file mode 100644 index 000000000..d87b37c58 --- /dev/null +++ b/libs/python/pyste/src/Pyste/Exporter.py @@ -0,0 +1,94 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/FunctionExporter.py b/libs/python/pyste/src/Pyste/FunctionExporter.py new file mode 100644 index 000000000..5765f65e9 --- /dev/null +++ b/libs/python/pyste/src/Pyste/FunctionExporter.py @@ -0,0 +1,92 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/GCCXMLParser.py b/libs/python/pyste/src/Pyste/GCCXMLParser.py new file mode 100644 index 000000000..4a1017204 --- /dev/null +++ b/libs/python/pyste/src/Pyste/GCCXMLParser.py @@ -0,0 +1,478 @@ +# 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') diff --git a/libs/python/pyste/src/Pyste/HeaderExporter.py b/libs/python/pyste/src/Pyste/HeaderExporter.py new file mode 100644 index 000000000..47651ba70 --- /dev/null +++ b/libs/python/pyste/src/Pyste/HeaderExporter.py @@ -0,0 +1,81 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/MultipleCodeUnit.py b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py new file mode 100644 index 000000000..65faad45d --- /dev/null +++ b/libs/python/pyste/src/Pyste/MultipleCodeUnit.py @@ -0,0 +1,135 @@ +# 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') + + + diff --git a/libs/python/pyste/src/Pyste/SingleCodeUnit.py b/libs/python/pyste/src/Pyste/SingleCodeUnit.py new file mode 100644 index 000000000..2e59dbb80 --- /dev/null +++ b/libs/python/pyste/src/Pyste/SingleCodeUnit.py @@ -0,0 +1,121 @@ +# 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() diff --git a/libs/python/pyste/src/Pyste/SmartFile.py b/libs/python/pyste/src/Pyste/SmartFile.py new file mode 100644 index 000000000..039579e3b --- /dev/null +++ b/libs/python/pyste/src/Pyste/SmartFile.py @@ -0,0 +1,60 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/VarExporter.py b/libs/python/pyste/src/Pyste/VarExporter.py new file mode 100644 index 000000000..d3571e751 --- /dev/null +++ b/libs/python/pyste/src/Pyste/VarExporter.py @@ -0,0 +1,40 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/__init__.py b/libs/python/pyste/src/Pyste/__init__.py new file mode 100644 index 000000000..02eec64b7 --- /dev/null +++ b/libs/python/pyste/src/Pyste/__init__.py @@ -0,0 +1,6 @@ +# 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) + + diff --git a/libs/python/pyste/src/Pyste/declarations.py b/libs/python/pyste/src/Pyste/declarations.py new file mode 100644 index 000000000..6eff97dc5 --- /dev/null +++ b/libs/python/pyste/src/Pyste/declarations.py @@ -0,0 +1,653 @@ +# 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) diff --git a/libs/python/pyste/src/Pyste/exporters.py b/libs/python/pyste/src/Pyste/exporters.py new file mode 100644 index 000000000..f573d01be --- /dev/null +++ b/libs/python/pyste/src/Pyste/exporters.py @@ -0,0 +1,12 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/exporterutils.py b/libs/python/pyste/src/Pyste/exporterutils.py new file mode 100644 index 000000000..363700d2b --- /dev/null +++ b/libs/python/pyste/src/Pyste/exporterutils.py @@ -0,0 +1,87 @@ +# 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 diff --git a/libs/python/pyste/src/Pyste/infos.py b/libs/python/pyste/src/Pyste/infos.py new file mode 100644 index 000000000..2a4f01eaf --- /dev/null +++ b/libs/python/pyste/src/Pyste/infos.py @@ -0,0 +1,259 @@ +# 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) diff --git a/libs/python/pyste/src/Pyste/policies.py b/libs/python/pyste/src/Pyste/policies.py new file mode 100644 index 000000000..57ebd0dea --- /dev/null +++ b/libs/python/pyste/src/Pyste/policies.py @@ -0,0 +1,95 @@ +# 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' diff --git a/libs/python/pyste/src/Pyste/pyste.py b/libs/python/pyste/src/Pyste/pyste.py new file mode 100644 index 000000000..cedffff55 --- /dev/null +++ b/libs/python/pyste/src/Pyste/pyste.py @@ -0,0 +1,424 @@ +# 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() diff --git a/libs/python/pyste/src/Pyste/settings.py b/libs/python/pyste/src/Pyste/settings.py new file mode 100644 index 000000000..ba613b234 --- /dev/null +++ b/libs/python/pyste/src/Pyste/settings.py @@ -0,0 +1,21 @@ +# 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' diff --git a/libs/python/pyste/src/Pyste/utils.py b/libs/python/pyste/src/Pyste/utils.py new file mode 100644 index 000000000..a8843e3f6 --- /dev/null +++ b/libs/python/pyste/src/Pyste/utils.py @@ -0,0 +1,78 @@ +# 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 diff --git a/libs/python/pyste/tests/GCCXMLParserUT.py b/libs/python/pyste/tests/GCCXMLParserUT.py new file mode 100644 index 000000000..7175c9c68 --- /dev/null +++ b/libs/python/pyste/tests/GCCXMLParserUT.py @@ -0,0 +1,341 @@ +# 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() diff --git a/libs/python/pyste/tests/SmartFileUT.py b/libs/python/pyste/tests/SmartFileUT.py new file mode 100644 index 000000000..9e4e99883 --- /dev/null +++ b/libs/python/pyste/tests/SmartFileUT.py @@ -0,0 +1,84 @@ +# 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() diff --git a/libs/python/pyste/tests/abstract_test.h b/libs/python/pyste/tests/abstract_test.h new file mode 100644 index 000000000..e0fba2b24 --- /dev/null +++ b/libs/python/pyste/tests/abstract_test.h @@ -0,0 +1,22 @@ +/* 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(); } + +} diff --git a/libs/python/pyste/tests/abstract_test.pyste b/libs/python/pyste/tests/abstract_test.pyste new file mode 100644 index 000000000..c65bb3ad6 --- /dev/null +++ b/libs/python/pyste/tests/abstract_test.pyste @@ -0,0 +1,3 @@ +Class('abstract::A', 'abstract_test.h') +Class('abstract::B', 'abstract_test.h') +Function('abstract::call', 'abstract_test.h') diff --git a/libs/python/pyste/tests/abstract_testUT.py b/libs/python/pyste/tests/abstract_testUT.py new file mode 100644 index 000000000..4dc61a262 --- /dev/null +++ b/libs/python/pyste/tests/abstract_testUT.py @@ -0,0 +1,26 @@ +# 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() diff --git a/libs/python/pyste/tests/add_test.h b/libs/python/pyste/tests/add_test.h new file mode 100644 index 000000000..447e8814c --- /dev/null +++ b/libs/python/pyste/tests/add_test.h @@ -0,0 +1,18 @@ +/* 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; +} + +} diff --git a/libs/python/pyste/tests/add_test.pyste b/libs/python/pyste/tests/add_test.pyste new file mode 100644 index 000000000..cc7faa9ed --- /dev/null +++ b/libs/python/pyste/tests/add_test.pyste @@ -0,0 +1,2 @@ +C = Class('add_test::C', 'add_test.h') +add_method(C, 'add_test::get_x') diff --git a/libs/python/pyste/tests/add_testUT.py b/libs/python/pyste/tests/add_testUT.py new file mode 100644 index 000000000..16f57a320 --- /dev/null +++ b/libs/python/pyste/tests/add_testUT.py @@ -0,0 +1,16 @@ +# 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() diff --git a/libs/python/pyste/tests/basic.cpp b/libs/python/pyste/tests/basic.cpp new file mode 100644 index 000000000..d07b6da62 --- /dev/null +++ b/libs/python/pyste/tests/basic.cpp @@ -0,0 +1,13 @@ +/* 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; + +} diff --git a/libs/python/pyste/tests/basic.h b/libs/python/pyste/tests/basic.h new file mode 100644 index 000000000..690fed2d3 --- /dev/null +++ b/libs/python/pyste/tests/basic.h @@ -0,0 +1,69 @@ +/* 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 diff --git a/libs/python/pyste/tests/basic.pyste b/libs/python/pyste/tests/basic.pyste new file mode 100644 index 000000000..4fe0b5b31 --- /dev/null +++ b/libs/python/pyste/tests/basic.pyste @@ -0,0 +1,5 @@ +Class('basic::C', 'basic.h') +Function('basic::call_f', 'basic.h') +Function('basic::get_static', 'basic.h') +Function('basic::get_value', 'basic.h') + diff --git a/libs/python/pyste/tests/basicUT.py b/libs/python/pyste/tests/basicUT.py new file mode 100644 index 000000000..9a18bcbf3 --- /dev/null +++ b/libs/python/pyste/tests/basicUT.py @@ -0,0 +1,73 @@ +# 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() diff --git a/libs/python/pyste/tests/code_test.h b/libs/python/pyste/tests/code_test.h new file mode 100644 index 000000000..0a31205a3 --- /dev/null +++ b/libs/python/pyste/tests/code_test.h @@ -0,0 +1,8 @@ +/* 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; +}; diff --git a/libs/python/pyste/tests/code_test.pyste b/libs/python/pyste/tests/code_test.pyste new file mode 100644 index 000000000..467996fdb --- /dev/null +++ b/libs/python/pyste/tests/code_test.pyste @@ -0,0 +1,9 @@ +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') diff --git a/libs/python/pyste/tests/code_testUT.py b/libs/python/pyste/tests/code_testUT.py new file mode 100644 index 000000000..1059570aa --- /dev/null +++ b/libs/python/pyste/tests/code_testUT.py @@ -0,0 +1,18 @@ +# 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() diff --git a/libs/python/pyste/tests/enums.h b/libs/python/pyste/tests/enums.h new file mode 100644 index 000000000..afe33ca48 --- /dev/null +++ b/libs/python/pyste/tests/enums.h @@ -0,0 +1,34 @@ +/* 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 diff --git a/libs/python/pyste/tests/enums.pyste b/libs/python/pyste/tests/enums.pyste new file mode 100644 index 000000000..c18a1244f --- /dev/null +++ b/libs/python/pyste/tests/enums.pyste @@ -0,0 +1,8 @@ +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') + diff --git a/libs/python/pyste/tests/enumsUT.py b/libs/python/pyste/tests/enumsUT.py new file mode 100644 index 000000000..7c7720dcb --- /dev/null +++ b/libs/python/pyste/tests/enumsUT.py @@ -0,0 +1,24 @@ +# 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() diff --git a/libs/python/pyste/tests/header_test.h b/libs/python/pyste/tests/header_test.h new file mode 100644 index 000000000..030d0d26c --- /dev/null +++ b/libs/python/pyste/tests/header_test.h @@ -0,0 +1,43 @@ +/* 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 diff --git a/libs/python/pyste/tests/header_test.pyste b/libs/python/pyste/tests/header_test.pyste new file mode 100644 index 000000000..3bd55501c --- /dev/null +++ b/libs/python/pyste/tests/header_test.pyste @@ -0,0 +1,4 @@ +h = AllFromHeader('header_test.h') +exclude(h.A) +exclude(h.foo) +exclude(h.bar) diff --git a/libs/python/pyste/tests/header_testUT.py b/libs/python/pyste/tests/header_testUT.py new file mode 100644 index 000000000..aa0d4a16f --- /dev/null +++ b/libs/python/pyste/tests/header_testUT.py @@ -0,0 +1,27 @@ +# 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() diff --git a/libs/python/pyste/tests/infosUT.py b/libs/python/pyste/tests/infosUT.py new file mode 100644 index 000000000..93769f34e --- /dev/null +++ b/libs/python/pyste/tests/infosUT.py @@ -0,0 +1,55 @@ +# 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() diff --git a/libs/python/pyste/tests/inherit.cpp b/libs/python/pyste/tests/inherit.cpp new file mode 100644 index 000000000..a75e83891 --- /dev/null +++ b/libs/python/pyste/tests/inherit.cpp @@ -0,0 +1,8 @@ +/* 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; diff --git a/libs/python/pyste/tests/inherit.h b/libs/python/pyste/tests/inherit.h new file mode 100644 index 000000000..8f903f4fd --- /dev/null +++ b/libs/python/pyste/tests/inherit.h @@ -0,0 +1,43 @@ +/* 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 {}; +} diff --git a/libs/python/pyste/tests/inherit.pyste b/libs/python/pyste/tests/inherit.pyste new file mode 100644 index 000000000..0dc029989 --- /dev/null +++ b/libs/python/pyste/tests/inherit.pyste @@ -0,0 +1,8 @@ +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) diff --git a/libs/python/pyste/tests/inherit2.h b/libs/python/pyste/tests/inherit2.h new file mode 100644 index 000000000..af9387bd0 --- /dev/null +++ b/libs/python/pyste/tests/inherit2.h @@ -0,0 +1,35 @@ +/* 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; } +}; + +} diff --git a/libs/python/pyste/tests/inherit2.pyste b/libs/python/pyste/tests/inherit2.pyste new file mode 100644 index 000000000..380821398 --- /dev/null +++ b/libs/python/pyste/tests/inherit2.pyste @@ -0,0 +1,2 @@ +Class('inherit2::B', 'inherit2.h') +Class('inherit2::D', 'inherit2.h') diff --git a/libs/python/pyste/tests/inherit2UT.py b/libs/python/pyste/tests/inherit2UT.py new file mode 100644 index 000000000..85afce617 --- /dev/null +++ b/libs/python/pyste/tests/inherit2UT.py @@ -0,0 +1,31 @@ +# 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() diff --git a/libs/python/pyste/tests/inherit3.h b/libs/python/pyste/tests/inherit3.h new file mode 100644 index 000000000..1945fb514 --- /dev/null +++ b/libs/python/pyste/tests/inherit3.h @@ -0,0 +1,46 @@ +/* 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 +{ +}; + +} diff --git a/libs/python/pyste/tests/inherit3.pyste b/libs/python/pyste/tests/inherit3.pyste new file mode 100644 index 000000000..f95c06054 --- /dev/null +++ b/libs/python/pyste/tests/inherit3.pyste @@ -0,0 +1,2 @@ +Class('inherit3::B', 'inherit3.h') +Class('inherit3::C', 'inherit3.h') diff --git a/libs/python/pyste/tests/inherit3UT.py b/libs/python/pyste/tests/inherit3UT.py new file mode 100644 index 000000000..b7dba1e93 --- /dev/null +++ b/libs/python/pyste/tests/inherit3UT.py @@ -0,0 +1,27 @@ +# 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() diff --git a/libs/python/pyste/tests/inherit4.h b/libs/python/pyste/tests/inherit4.h new file mode 100644 index 000000000..a1cecfbc8 --- /dev/null +++ b/libs/python/pyste/tests/inherit4.h @@ -0,0 +1,23 @@ +/* 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; +}; + +} diff --git a/libs/python/pyste/tests/inherit4.pyste b/libs/python/pyste/tests/inherit4.pyste new file mode 100644 index 000000000..4809e022f --- /dev/null +++ b/libs/python/pyste/tests/inherit4.pyste @@ -0,0 +1,3 @@ +Class('inherit4::A', 'inherit4.h') +Class('inherit4::B', 'inherit4.h') +Class('inherit4::C', 'inherit4.h') diff --git a/libs/python/pyste/tests/inherit4UT.py b/libs/python/pyste/tests/inherit4UT.py new file mode 100644 index 000000000..f2c75c553 --- /dev/null +++ b/libs/python/pyste/tests/inherit4UT.py @@ -0,0 +1,31 @@ +# 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() diff --git a/libs/python/pyste/tests/inheritUT.py b/libs/python/pyste/tests/inheritUT.py new file mode 100644 index 000000000..f3e7b4062 --- /dev/null +++ b/libs/python/pyste/tests/inheritUT.py @@ -0,0 +1,33 @@ +# 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() diff --git a/libs/python/pyste/tests/nested.cpp b/libs/python/pyste/tests/nested.cpp new file mode 100644 index 000000000..6e167ab06 --- /dev/null +++ b/libs/python/pyste/tests/nested.cpp @@ -0,0 +1,9 @@ +/* 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; diff --git a/libs/python/pyste/tests/nested.h b/libs/python/pyste/tests/nested.h new file mode 100644 index 000000000..13ed60856 --- /dev/null +++ b/libs/python/pyste/tests/nested.h @@ -0,0 +1,32 @@ +/* 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 diff --git a/libs/python/pyste/tests/nested.pyste b/libs/python/pyste/tests/nested.pyste new file mode 100644 index 000000000..48bb26b55 --- /dev/null +++ b/libs/python/pyste/tests/nested.pyste @@ -0,0 +1 @@ +Class('nested::Root', 'nested.h') diff --git a/libs/python/pyste/tests/nestedUT.py b/libs/python/pyste/tests/nestedUT.py new file mode 100644 index 000000000..06c1c7beb --- /dev/null +++ b/libs/python/pyste/tests/nestedUT.py @@ -0,0 +1,19 @@ +# 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() diff --git a/libs/python/pyste/tests/opaque.h b/libs/python/pyste/tests/opaque.h new file mode 100644 index 000000000..1947830ea --- /dev/null +++ b/libs/python/pyste/tests/opaque.h @@ -0,0 +1,57 @@ +/* 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 diff --git a/libs/python/pyste/tests/opaque.pyste b/libs/python/pyste/tests/opaque.pyste new file mode 100644 index 000000000..8180d251c --- /dev/null +++ b/libs/python/pyste/tests/opaque.pyste @@ -0,0 +1,7 @@ +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)) diff --git a/libs/python/pyste/tests/opaqueUT.py b/libs/python/pyste/tests/opaqueUT.py new file mode 100644 index 000000000..0f3e1e073 --- /dev/null +++ b/libs/python/pyste/tests/opaqueUT.py @@ -0,0 +1,24 @@ +# 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 _opaque import * + +class OpaqueTest(unittest.TestCase): + + def testIt(self): + + c = new_C() + self.assertEqual(get(c), 10) + c = new_C_zero() + self.assertEqual(get(c), 0) + a = A() + d = a.new_handle() + self.assertEqual(a.get(d), 3.0) + self.assertEqual(a.f(), 0) + self.assertEqual(a.f(3), 3) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/operators.cpp b/libs/python/pyste/tests/operators.cpp new file mode 100644 index 000000000..cecdaca0d --- /dev/null +++ b/libs/python/pyste/tests/operators.cpp @@ -0,0 +1,8 @@ +/* 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 "operators.h" + +double operators::C::x = 10; diff --git a/libs/python/pyste/tests/operators.h b/libs/python/pyste/tests/operators.h new file mode 100644 index 000000000..5d3944216 --- /dev/null +++ b/libs/python/pyste/tests/operators.h @@ -0,0 +1,52 @@ +/* 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 OPERATORS_H +#define OPERATORS_H + + +namespace operators { + +struct C +{ + static double x; + double value; + + const C operator+(const C other) const + { + C c; + c.value = value + other.value; + return c; + } + operator int() const + { + return (int)value; + } + + double operator()() + { + return C::x; + } + + double operator()(double other) + { + return C::x + other; + } + + operator const char*() { return "C"; } +}; + +inline const C operator*(const C& lhs, const C& rhs) +{ + C c; + c.value = lhs.value * rhs.value; + return c; +} + + +} + + +#endif diff --git a/libs/python/pyste/tests/operators.pyste b/libs/python/pyste/tests/operators.pyste new file mode 100644 index 000000000..4ab7a3709 --- /dev/null +++ b/libs/python/pyste/tests/operators.pyste @@ -0,0 +1,2 @@ +C = Class('operators::C', 'operators.h') +#exclude(C.operator['+']) diff --git a/libs/python/pyste/tests/operatorsUT.py b/libs/python/pyste/tests/operatorsUT.py new file mode 100644 index 000000000..beb193173 --- /dev/null +++ b/libs/python/pyste/tests/operatorsUT.py @@ -0,0 +1,30 @@ +# 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 _operators import * + +class OperatorTest(unittest.TestCase): + + def testIt(self): + c = C() + c.value = 3.0 + d = C() + d.value = 2.0 + self.assertEqual(c.x, 10) + self.assertEqual(C.x, 10) + self.assertEqual(C.x, 10) + self.assertEqual((c * d).value, 6.0) + self.assertEqual((c + d).value, 5.0) + self.assertEqual(int(c), 3) + self.assertEqual(int(d), 2) + self.assertEqual(c(), 10) + self.assertEqual(d(), 10) + self.assertEqual(c(3.0), 13.0) + self.assertEqual(d(6.0), 16.0) + self.assertEqual(str(c), "C") + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/policiesUT.py b/libs/python/pyste/tests/policiesUT.py new file mode 100644 index 000000000..7255baeb4 --- /dev/null +++ b/libs/python/pyste/tests/policiesUT.py @@ -0,0 +1,67 @@ +# 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 +import unittest +from Pyste.policies import * + + +#================================================================================ +# PolicicesTest +#================================================================================ +class PoliciesTest(unittest.TestCase): + + def testReturnInternal(self): + 'tests the code from a simple internal_reference' + + x = return_internal_reference(1) + self.assertEqual(x.Code(), 'return_internal_reference< 1 >') + x = return_internal_reference(3) + self.assertEqual(x.Code(), 'return_internal_reference< 3 >') + + + def testCustodian(self): + 'tests the code from a simple custodian_and_ward' + + x = with_custodian_and_ward(1,2) + self.assertEqual(x.Code(), 'with_custodian_and_ward< 1, 2 >') + x = with_custodian_and_ward(3,4) + self.assertEqual(x.Code(), 'with_custodian_and_ward< 3, 4 >') + + + def testReturnPolicies(self): + 'tests all the return_value_policies' + + ret = 'return_value_policy< %s >' + x = return_value_policy(reference_existing_object) + self.assertEqual(x.Code(), ret % 'reference_existing_object') + x = return_value_policy(copy_const_reference) + self.assertEqual(x.Code(), ret % 'copy_const_reference') + x = return_value_policy(copy_non_const_reference) + self.assertEqual(x.Code(), ret % 'copy_non_const_reference') + x = return_value_policy(manage_new_object) + self.assertEqual(x.Code(), ret % 'manage_new_object') + x = return_value_policy(return_opaque_pointer) + self.assertEqual(x.Code(), ret % 'return_opaque_pointer') + + def testReturnWithCustodiam(self): + 'test the mix of return_internal with custodian' + + x = return_internal_reference(1, with_custodian_and_ward(3,2)) + self.assertEqual( + x.Code(), + 'return_internal_reference< 1, with_custodian_and_ward< 3, 2 > >') + + + def testReturnPoliciesWithInternal(self): + 'test the mix of return_internal with return_policy' + + x = return_internal_reference(1, return_value_policy(manage_new_object)) + self.assertEqual( + x.Code(), + 'return_internal_reference< 1, return_value_policy< manage_new_object > >') + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/runtests.py b/libs/python/pyste/tests/runtests.py new file mode 100644 index 000000000..4bf83b345 --- /dev/null +++ b/libs/python/pyste/tests/runtests.py @@ -0,0 +1,21 @@ +# 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) +#!/usr/bin/python + +import sys +sys.path.append('../src/Pyste') +import unittest +import os.path +from glob import glob + +if __name__ == '__main__': + loader = unittest.defaultTestLoader + tests = [] + for name in glob('*UT.py'): + module = __import__(os.path.splitext(name)[0]) + tests.append(loader.loadTestsFromModule(module)) + runner = unittest.TextTestRunner() + result = runner.run(unittest.TestSuite(tests)) + sys.exit(not result.wasSuccessful()) diff --git a/libs/python/pyste/tests/smart_ptr.h b/libs/python/pyste/tests/smart_ptr.h new file mode 100644 index 000000000..b230b9179 --- /dev/null +++ b/libs/python/pyste/tests/smart_ptr.h @@ -0,0 +1,50 @@ +/* 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 SMART_PTR_H +#define SMART_PTR_H + + +#include <memory> +#include <boost/shared_ptr.hpp> + +namespace smart_ptr { + +struct C +{ + int value; +}; + +inline boost::shared_ptr<C> NewC() { return boost::shared_ptr<C>( new C() ); } + +struct D +{ + boost::shared_ptr<C> Get() { return ptr; } + void Set( boost::shared_ptr<C> c ) { ptr = c; } +private: + boost::shared_ptr<C> ptr; +}; + +inline std::auto_ptr<D> NewD() { return std::auto_ptr<D>( new D() ); } + + +// test an abstract class +struct A +{ + virtual int f() = 0; +}; + +struct B: A +{ + virtual int f(){ return 1; } +}; + +inline boost::shared_ptr<A> NewA() { return boost::shared_ptr<A>(new B()); } +inline int GetA(boost::shared_ptr<A> a) { return a->f(); } + +} + +#endif diff --git a/libs/python/pyste/tests/smart_ptr.pyste b/libs/python/pyste/tests/smart_ptr.pyste new file mode 100644 index 000000000..cfbdd81ae --- /dev/null +++ b/libs/python/pyste/tests/smart_ptr.pyste @@ -0,0 +1,13 @@ +C = Class('smart_ptr::C', 'smart_ptr.h') +use_shared_ptr(C) + +D = Class('smart_ptr::D', 'smart_ptr.h') +use_auto_ptr(D) + +A = Class('smart_ptr::A', 'smart_ptr.h') +use_shared_ptr(A) + +Function('smart_ptr::NewC', 'smart_ptr.h') +Function('smart_ptr::NewD', 'smart_ptr.h') +Function('smart_ptr::NewA', 'smart_ptr.h') +Function('smart_ptr::GetA', 'smart_ptr.h') diff --git a/libs/python/pyste/tests/smart_ptrUT.py b/libs/python/pyste/tests/smart_ptrUT.py new file mode 100644 index 000000000..9d81f08dd --- /dev/null +++ b/libs/python/pyste/tests/smart_ptrUT.py @@ -0,0 +1,22 @@ +# 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 _smart_ptr import * + +class BasicExampleTest(unittest.TestCase): + + def testIt(self): + c = NewC() + d = NewD() + c.value = 3 + d.Set(c) + c1 = d.Get() + c1.value = 6 + self.assertEqual(c.value, 6) + a = NewA() + self.assertEqual(GetA(a), 1) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/templates.h b/libs/python/pyste/tests/templates.h new file mode 100644 index 000000000..7258e91c7 --- /dev/null +++ b/libs/python/pyste/tests/templates.h @@ -0,0 +1,15 @@ +/* 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 templates { + +template <class T> +struct Point +{ + T x; + T y; +}; + +} diff --git a/libs/python/pyste/tests/templates.pyste b/libs/python/pyste/tests/templates.pyste new file mode 100644 index 000000000..77eaceaa3 --- /dev/null +++ b/libs/python/pyste/tests/templates.pyste @@ -0,0 +1,8 @@ +Point = Template('templates::Point', 'templates.h') +rename(Point.x, 'i') +rename(Point.y, 'j') +IPoint = Point('int') +FPoint = Point('double', 'FPoint') +rename(IPoint, 'IPoint') +rename(IPoint.x, 'x') +rename(IPoint.y, 'y') diff --git a/libs/python/pyste/tests/templatesUT.py b/libs/python/pyste/tests/templatesUT.py new file mode 100644 index 000000000..0c4b08b50 --- /dev/null +++ b/libs/python/pyste/tests/templatesUT.py @@ -0,0 +1,30 @@ +# 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 _templates import * + +class TemplatesTest(unittest.TestCase): + + def testIt(self): + fp = FPoint() + fp.i = 3.0 + fp.j = 4.0 + ip = IPoint() + ip.x = 10 + ip.y = 3 + + self.assertEqual(fp.i, 3.0) + self.assertEqual(fp.j, 4.0) + self.assertEqual(ip.x, 10) + self.assertEqual(ip.y, 3) + self.assertEqual(type(fp.i), float) + self.assertEqual(type(fp.j), float) + self.assertEqual(type(ip.x), int) + self.assertEqual(type(ip.y), int) + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/test_all.py b/libs/python/pyste/tests/test_all.py new file mode 100644 index 000000000..ba3c54dee --- /dev/null +++ b/libs/python/pyste/tests/test_all.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# 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 glob +import shutil +import sys +import time + +#============================================================================= +# win32 configuration +#============================================================================= +if sys.platform == 'win32': + + includes = '-ID:/programming/libraries/boost-cvs/boost -ID:/Bin/Python/include' + build_pyste_cmd = 'python ../src/Pyste/pyste.py --pyste-ns=pyste --cache-dir=cache %s ' % includes + compile_single_cmd = 'cl /nologo /GR /GX -c %s -I. ' % includes + link_single_cmd = 'link /nologo /DLL '\ + '/libpath:D:/programming/libraries/boost-cvs/lib /libpath:D:/Bin/Python/libs '\ + 'boost_python.lib python24.lib /out:_%s.dll ' + obj_ext = 'obj' + +#============================================================================= +# linux configuration +#============================================================================= +elif sys.platform == 'linux2': + + build_pyste_cmd = 'python ../src/Pyste/pyste.py -I. ' + compile_single_cmd = 'g++ -shared -c -I. -I/usr/include/python2.4 ' + link_single_cmd = 'g++ -shared -o _%s.so -lboost_python ' + obj_ext = 'o' + + + +def build_pyste(multiple, module): + rest = '%s --module=_%s %s.pyste' % (multiple, module, module) + execute(build_pyste_cmd + rest) + + +def compile_single(module): + module_obj = '' + if os.path.isfile(module+'.cpp'): + execute(compile_single_cmd + module+'.cpp') + module_obj = module + '.' + obj_ext + execute(compile_single_cmd + ('_%s.cpp' % module)) + link = link_single_cmd % module + execute(link + ('_%s.%s ' % (module, obj_ext)) + module_obj) + + +def compile_multiple(module): + module_obj = '' + if os.path.isfile(module+'.cpp'): + execute(compile_single_cmd + module+'.cpp') + module_obj = module + '.' + obj_ext + files = glob.glob('_%s/*.cpp' % module) + for f in files: + execute(compile_single_cmd + f) + def basename(name): + return os.path.basename(os.path.splitext(name)[0]) + objs = [basename(x) + '.' + obj_ext for x in files] + objs.append(module_obj) + execute((link_single_cmd % module) + ' '.join(objs)) + + +def execute(cmd): + os.system(cmd) + + +def run_tests(): + if os.system('python runtests.py') != 0: + raise RuntimeError, 'tests failed' + + +def cleanup(): + modules = get_modules() + extensions = '*.dll *.pyc *.obj *.exp *.lib *.o *.so' + files = [] + for module in modules: + files.append('_' + module + '.cpp') + for ext in extensions.split(): + files += glob.glob(ext) + files.append('build.log') + for file in files: + try: + os.remove(file) + except OSError: pass + + for module in modules: + try: + shutil.rmtree('_' + module) + except OSError: pass + + +def main(multiple, module=None): + if module is None: + modules = get_modules() + else: + modules = [module] + + start = time.clock() + for module in modules: + build_pyste(multiple, module) + print '-'*50 + print 'Building pyste files: %0.2f seconds' % (time.clock()-start) + print + + start = time.clock() + for module in modules: + if multiple: + compile_multiple(module) + else: + compile_single(module) + print '-'*50 + print 'Compiling files: %0.2f seconds' % (time.clock()-start) + print + if len(modules) == 1: + os.system('python %sUT.py' % modules[0]) + else: + run_tests() + #cleanup() + + +def get_modules(): + def getname(file): + return os.path.splitext(os.path.basename(file))[0] + return [getname(x) for x in glob.glob('*.pyste')] + +if __name__ == '__main__': + if len(sys.argv) > 1: + module = sys.argv[1] + else: + module = None + try: +# main('--multiple', module) + main('', module) + except RuntimeError, e: + print e diff --git a/libs/python/pyste/tests/vars.cpp b/libs/python/pyste/tests/vars.cpp new file mode 100644 index 000000000..e2abcd332 --- /dev/null +++ b/libs/python/pyste/tests/vars.cpp @@ -0,0 +1,12 @@ +/* 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 "vars.h" + +const Color black = Color(0, 0, 0); +const Color red = Color(255, 0, 0); +const Color green = Color(0, 255, 0); +const Color blue = Color(0, 0, 255); +Color in_use = black; diff --git a/libs/python/pyste/tests/vars.h b/libs/python/pyste/tests/vars.h new file mode 100644 index 000000000..24e87d802 --- /dev/null +++ b/libs/python/pyste/tests/vars.h @@ -0,0 +1,24 @@ +/* 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 Color +{ + Color(int r_ = 0, int g_ = 0, int b_ = 0): + r(r_), g(g_), b(b_) + {} + Color( const Color &c): + r(c.r), g(c.g), b(c.b) + {} + int r; + int g; + int b; +}; + +extern const Color black; +extern const Color red; +extern const Color green; +extern const Color blue; +extern Color in_use; diff --git a/libs/python/pyste/tests/vars.pyste b/libs/python/pyste/tests/vars.pyste new file mode 100644 index 000000000..3fd9d689d --- /dev/null +++ b/libs/python/pyste/tests/vars.pyste @@ -0,0 +1 @@ +AllFromHeader('vars.h') diff --git a/libs/python/pyste/tests/varsUT.py b/libs/python/pyste/tests/varsUT.py new file mode 100644 index 000000000..4c32cbb2f --- /dev/null +++ b/libs/python/pyste/tests/varsUT.py @@ -0,0 +1,22 @@ +# 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 +import _vars + + +class VarsTest(unittest.TestCase): + + def testIt(self): + def testColor(c, r, g, b): + self.assertEqual(c.r, r) + self.assertEqual(c.g, g) + self.assertEqual(c.b, b) + testColor(_vars.black, 0, 0, 0) + testColor(_vars.red, 255, 0, 0) + testColor(_vars.green, 0, 255, 0) + testColor(_vars.blue, 0, 0, 255) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/virtual.cpp b/libs/python/pyste/tests/virtual.cpp new file mode 100644 index 000000000..070d9d346 --- /dev/null +++ b/libs/python/pyste/tests/virtual.cpp @@ -0,0 +1,75 @@ +/* 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) + */ + +// Includes ==================================================================== +#include <boost/python.hpp> +#include <virtual.h> + +// Using ======================================================================= +using namespace boost::python; + +// Declarations ================================================================ + + +namespace { + + +struct virtual_C_Wrapper: virtual_::C +{ + virtual_C_Wrapper(PyObject* self_, const virtual_::C & p0): + virtual_::C(p0), self(self_) {} + + virtual_C_Wrapper(PyObject* self_): + virtual_::C(), self(self_) {} + + int f() { + return call_method< int >(self, "f"); + } + + int default_f() { + return virtual_::C::f(); + } + + void bar(int p0) { + call_method< void >(self, "bar", p0); + } + + void default_bar(int p0) { + virtual_::C::bar(p0); + } + + void bar(char * p0) { + call_method< void >(self, "bar", p0); + } + + void default_bar(char * p0) { + virtual_::C::bar(p0); + } + + int f_abs() { + return call_method< int >(self, "f_abs"); + } + + PyObject* self; +}; + + + +}// namespace + + +// Module ====================================================================== +BOOST_PYTHON_MODULE(virtual) +{ + class_< virtual_::C, boost::noncopyable, virtual_C_Wrapper >("C", init< >()) + .def("get_name", &virtual_::C::get_name) + .def("f", &virtual_::C::f, &virtual_C_Wrapper::default_f) + .def("bar", (void (virtual_::C::*)(int) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(int))&virtual_C_Wrapper::default_bar) + .def("bar", (void (virtual_::C::*)(char *) )&virtual_::C::bar, (void (virtual_C_Wrapper::*)(char *))&virtual_C_Wrapper::default_bar) + ; + + def("call_f", &virtual_::call_f); +} diff --git a/libs/python/pyste/tests/virtual.h b/libs/python/pyste/tests/virtual.h new file mode 100644 index 000000000..d0bb194a1 --- /dev/null +++ b/libs/python/pyste/tests/virtual.h @@ -0,0 +1,41 @@ +/* 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 virtual_ { + +struct C +{ +public: + virtual int f() + { + return f_abs(); + } + + virtual void bar(int) {} + virtual void bar(char*) {} + + const char* get_name() + { + return name(); + } + virtual int dummy() { return 0; } + +protected: + virtual int f_abs() = 0; + +private: + virtual const char* name() { return "C"; } +}; + +struct D +{ + virtual int dummy() { return 0; } +}; + +inline int call_f(C& c) { return c.f(); } +inline int call_dummy(C* c) { return c->dummy(); } +inline int call_dummy(D* d) { return d->dummy(); } + +} diff --git a/libs/python/pyste/tests/virtual.pyste b/libs/python/pyste/tests/virtual.pyste new file mode 100644 index 000000000..ef9664124 --- /dev/null +++ b/libs/python/pyste/tests/virtual.pyste @@ -0,0 +1,6 @@ +C = Class('virtual_::C', 'virtual.h') +final(C.dummy) +D = Class('virtual_::D', 'virtual.h') +final(D.dummy) +Function('virtual_::call_f', 'virtual.h') +Function('virtual_::call_dummy', 'virtual.h') diff --git a/libs/python/pyste/tests/virtual2.h b/libs/python/pyste/tests/virtual2.h new file mode 100644 index 000000000..a6677ad16 --- /dev/null +++ b/libs/python/pyste/tests/virtual2.h @@ -0,0 +1,34 @@ +/* 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 virtual2 { + +struct A +{ + virtual int f() { return 0; } + virtual int f1() { return 10; } + virtual A* make_new() { return new A; } +}; + +struct B: A +{ + virtual int f() { return 1; } + virtual int f2() { return 20; } + virtual A* make_new() { return new B; } +}; + +inline int call_fs(A*a) +{ + int r = a->f1(); + B* b = dynamic_cast<B*>(a); + return r + b->f2(); +} + +inline int call_f(A* a) +{ + return a->f(); +} +} diff --git a/libs/python/pyste/tests/virtual2.pyste b/libs/python/pyste/tests/virtual2.pyste new file mode 100644 index 000000000..785b819c8 --- /dev/null +++ b/libs/python/pyste/tests/virtual2.pyste @@ -0,0 +1,6 @@ +A = Class('virtual2::A', 'virtual2.h') +set_policy(A.make_new, return_value_policy(manage_new_object)) +B = Class('virtual2::B', 'virtual2.h') +set_policy(B.make_new, return_value_policy(manage_new_object)) +Function('virtual2::call_fs', 'virtual2.h') +Function('virtual2::call_f', 'virtual2.h') diff --git a/libs/python/pyste/tests/virtual2UT.py b/libs/python/pyste/tests/virtual2UT.py new file mode 100644 index 000000000..312277d26 --- /dev/null +++ b/libs/python/pyste/tests/virtual2UT.py @@ -0,0 +1,40 @@ +# 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 _virtual2 import * + +class Virtual2Test(unittest.TestCase): + + def testIt(self): + a = A() + self.assertEqual(a.f1(), 10) + b = B() + self.assertEqual(b.f1(), 10) + self.assertEqual(b.f2(), 20) + self.assertEqual(call_fs(b), 30) + self.assertEqual(call_f(a), 0) + self.assertEqual(call_f(b), 1) + nb = b.make_new() + na = a.make_new() + self.assertEqual(na.f1(), 10) + self.assertEqual(nb.f1(), 10) + self.assertEqual(nb.f2(), 20) + self.assertEqual(call_fs(nb), 30) + self.assertEqual(call_f(na), 0) + self.assertEqual(call_f(nb), 1) + class C(B): + def f1(self): return 1 + def f2(self): return 2 + def f(self): return 100 + + c = C() + self.assertEqual(call_fs(c), 3) + self.assertEqual(call_fs(c), 3) + self.assertEqual(call_f(c), 100) + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/virtualUT.py b/libs/python/pyste/tests/virtualUT.py new file mode 100644 index 000000000..deff68189 --- /dev/null +++ b/libs/python/pyste/tests/virtualUT.py @@ -0,0 +1,55 @@ +# 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 _virtual import * + +class VirtualTest(unittest.TestCase): + + def testIt(self): + + class E(C): + def f_abs(self): + return 3 + def dummy(self): + # override should not work + return 100 + + class F(C): + def f(self): + return 10 + def name(self): + return 'F' + + class G(D): + def dummy(self): + # override should not work + return 100 + + e = E() + f = F() + + self.assertEqual(e.f(), 3) + self.assertEqual(call_f(e), 3) + self.assertEqual(f.f(), 10) + self.assertEqual(call_f(f), 10) + self.assertEqual(e.get_name(), 'C') + #self.assertEqual(e.get_name(), 'E') check this later + + c = C() + c.bar(1) # ok + c.bar('a') # ok + self.assertRaises(TypeError, c.bar, 1.0) + + # test no_overrides + d = G() + self.assertEqual(e.dummy(), 100) + self.assertEqual(call_dummy(e), 0) + self.assertEqual(d.dummy(), 100) + self.assertEqual(call_dummy(d), 0) + + + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/wrappertest.h b/libs/python/pyste/tests/wrappertest.h new file mode 100644 index 000000000..2304fd843 --- /dev/null +++ b/libs/python/pyste/tests/wrappertest.h @@ -0,0 +1,51 @@ +/* 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 WRAPPER_TEST +#define WRAPPER_TEST + + +#include <vector> + +namespace wrappertest { + +inline std::vector<int> Range(int count) +{ + std::vector<int> v; + v.reserve(count); + for (int i = 0; i < count; ++i){ + v.push_back(i); + } + return v; +} + + +struct C +{ + C() {} + + std::vector<int> Mul(int value) + { + std::vector<int> res; + res.reserve(value); + std::vector<int>::const_iterator it; + std::vector<int> v(Range(value)); + for (it = v.begin(); it != v.end(); ++it){ + res.push_back(*it * value); + } + return res; + } +}; + + +struct A +{ + virtual int f() { return 1; }; +}; + +inline int call_foo(A* a){ return a->f(); } +} +#endif + diff --git a/libs/python/pyste/tests/wrappertest.pyste b/libs/python/pyste/tests/wrappertest.pyste new file mode 100644 index 000000000..12ba47b6b --- /dev/null +++ b/libs/python/pyste/tests/wrappertest.pyste @@ -0,0 +1,21 @@ +Include('wrappertest_wrappers.h') + +f = Function('wrappertest::Range', 'wrappertest.h') +set_wrapper(f, 'RangeWrapper') + +mul = Wrapper('MulWrapper', +''' +list MulWrapper(wrappertest::C& c, int value){ + return VectorToList(c.Mul(value)); +} +''' +) + +C = Class('wrappertest::C', 'wrappertest.h') +set_wrapper(C.Mul, mul) + + +A = Class('wrappertest::A', 'wrappertest.h') +set_wrapper(A.f, 'f_wrapper') + +Function('wrappertest::call_foo', 'wrappertest.h') diff --git a/libs/python/pyste/tests/wrappertestUT.py b/libs/python/pyste/tests/wrappertestUT.py new file mode 100644 index 000000000..d770408b7 --- /dev/null +++ b/libs/python/pyste/tests/wrappertestUT.py @@ -0,0 +1,24 @@ +# 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 _wrappertest import * + +class WrapperTest(unittest.TestCase): + + def testIt(self): + self.assertEqual(Range(10), range(10)) + self.assertEqual(C().Mul(10), [x*10 for x in range(10)]) + + a = A() + self.assertEqual(a.f(), 10) + self.assertEqual(call_foo(a), 10) + class D(A): + def f(self): return 2 + d = D() + self.assertEqual(d.f(), 2) + self.assertEqual(call_foo(d), 2) + +if __name__ == '__main__': + unittest.main() diff --git a/libs/python/pyste/tests/wrappertest_wrappers.h b/libs/python/pyste/tests/wrappertest_wrappers.h new file mode 100644 index 000000000..31570a051 --- /dev/null +++ b/libs/python/pyste/tests/wrappertest_wrappers.h @@ -0,0 +1,33 @@ +/* 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 WRAPPER_TEST_WRAPPERS +#define WRAPPER_TEST_WRAPPERS + +#include <vector> +#include <boost/python.hpp> +#include "wrappertest.h" + +using namespace boost::python; + +template <class T> +list VectorToList(const std::vector<T> & v) +{ + list res; + typename std::vector<T>::const_iterator it; + for(it = v.begin(); it != v.end(); ++it){ + res.append(*it); + } + Py_XINCREF(res.ptr()); + return res; +} + +inline list RangeWrapper(int count){ + return VectorToList(wrappertest::Range(count)); +} + +inline int f_wrapper(wrappertest::A*) { return 10; } + +#endif |