2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 04:22:16 +00:00

- first version

[SVN r17805]
This commit is contained in:
Bruno da Silva de Oliveira
2003-03-11 03:29:22 +00:00
parent 7dcacbcfc4
commit 20c52def19
48 changed files with 4224 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Exporting All Declarations from a Header</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="wrappers.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
<tr>
<td><img src="theme/c%2B%2Bboost.gif">
</td>
<td width="85%">
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Exporting All Declarations from a 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"><img src="theme/r_arr_disabled.gif" border="0"></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>-&gt;</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>&lt;&lt; </span><span class=string>&quot;value: &quot; </span><span class=special>&lt;&lt; (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special>&lt;&lt; </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>&quot;hello.h&quot;</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>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>Enum</span><span class=special>(</span><span class=string>&quot;choice&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>Function</span><span class=special>(</span><span class=string>&quot;show&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</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>&quot;Greet&quot;</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>&quot;Set&quot;</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="wrappers.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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

View File

@@ -0,0 +1,74 @@
<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="theme/c%2B%2Bboost.gif">
</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/exposing_classes.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>-&gt;</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>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;world.h&quot;</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 &quot;<tt>hello.cpp</tt>&quot; 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 &quot;free&quot; enums and class enums)</li><li>Nested Classes</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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

79
pyste/doc/policies.html Normal file
View File

@@ -0,0 +1,79 @@
<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="theme/c%2B%2Bboost.gif">
</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
methods, attributes, and so on, one thing that it can't do is to guess the
semantics of functions that return pointers or references. In this case, the
user must manually specify the policy. Policies are explained in the
<a href="../../doc/tutorial/doc/call_policies.html">
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>&lt;</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special>&lt;</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>&gt; &gt;()
</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 methods 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 method needs a policy and the user
doesn't set one?</b><br><br>
If a function/method needs a policy and one was not set, Pyste will issue a error.
The user should then go in the interface file and set the policy for it,
otherwise the generated cpp won't compile.
</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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

370
pyste/doc/pyste.txt Normal file
View File

@@ -0,0 +1,370 @@
[doc Pyste Documentation]
[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
[page Running Pyste]
To run pyste, you will need:
* Python 2.2, avaiable 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 avaiable 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
Usage:
pyste [options] --module=<name> interface-files
where options are:
-I <path> add an include path
-D <symbol> define symbol
--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 "pyste"
'''
]
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.
[^--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 one of your header files declare a
namespace named "pyste" and this is causing conflicts.
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. Windows users should run the [^Vcvars32.bat] file,
normally located at:
C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat
with that, you should have little trouble setting up the flags.
[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 classes and methods, excluding methods and attributes,
and so 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].
[page:1 Renaming and Excluding]
You can easily rename functions, classes, methods, 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 methods 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, methods, attributes, etc, in the same way,
with the function [^exclude]:
exclude(World.greet)
exclude(World.msg)
Easy, huh? [$theme/smiley.gif]
[page:1 Policies]
Even thought Pyste can identify various elements in the C++ code, like virtual
methods, attributes, and so on, one thing that it can't do is to guess the
semantics of functions that return pointers or references. In this case, the
user must manually specify the policy. Policies are explained in the
[@../../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 methods with the [^set_policy]
function:
set_policy(f, return_internal_reference())
set_policy(C.foo, return_value_policy(manage_new_object))
[blurb
[$theme/note.gif] [*What if a function or method needs a policy and the user
doesn't set one?][br][br]
If a function/method needs a policy and one was not set, Pyste will issue a error.
The user should then go in the interface file and set the policy for it,
otherwise the generated cpp won't compile.
]
[page:1 Templates]
Template Classes can easily 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] class
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 export a vector<string>, you want this function to return
a python list of strings. Boost.Python has an excellent support for that:
list names_wrapper()
{
list result;
vector<string> v = names();
// put each string in the vector in the list
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, like "[^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()
{
// call name() and convert the vector to a list...
}
""")
names = Function("names", "test.h")
set_wrapper(names, names_wrapper)
The same mechanism can be done with methods too. Just remember that the first
parameter of wrappers for methods is a pointer to the class, like in
Boost.Python:
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")
[page:1 Exporting All Declarations from a 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")

View File

@@ -0,0 +1,68 @@
<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="theme/c%2B%2Bboost.gif">
</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, methods, attributes, etc. Just use the
function <tt>rename</tt>, like this:</p>
<code><pre>
<span class=identifier>World </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>, </span><span class=string>&quot;IWorld&quot;</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>&quot;choice&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</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>&quot;Show&quot;</span><span class=special>)
</span></pre></code>
<p>
You can rename methods and attributes using this syntax:</p>
<code><pre>
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>&quot;Greet&quot;</span><span class=special>)
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>&quot;Set&quot;</span><span class=special>)
</span><span class=identifier>choice </span><span class=special>= </span><span class=identifier>Enum</span><span class=special>(</span><span class=string>&quot;choice&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</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>&quot;Red&quot;</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>&quot;Blue&quot;</span><span class=special>)
</span></pre></code>
<p>
You can exclude functions, classes, methods, 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>
Easy, huh? <img src="theme/smiley.gif"></img></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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

View File

@@ -0,0 +1,110 @@
<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="theme/c%2B%2Bboost.gif">
</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, avaiable 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 avaiable 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>
&gt;python pyste.py
Usage:
pyste [options] --module=&lt;name&gt; interface-files
where options are:
-I &lt;path&gt; add an include path
-D &lt;symbol&gt; define symbol
--no-using do not declare &quot;using namespace boost&quot;;
use explicit declarations instead
--pyste-ns=&lt;name&gt; set the namespace where new types will be declared;
default is &quot;pyste&quot;
</pre></code><p>
Options explained:</p>
<p>
The <tt>-I</tt> and <tt>-D</tt> 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.</p>
<p>
<tt>--no-using</tt> tells pyste to don't declare &quot;<tt>using namespace boost;</tt>&quot; 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 one of your header files declare a
namespace named &quot;pyste&quot; and this is causing conflicts.</p>
<p>
So, the usage is simple enough:</p>
<code><pre>&gt;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/building_hello_world.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. Windows users should run the <tt>Vcvars32.bat</tt> file,
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 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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

103
pyste/doc/templates.html Normal file
View File

@@ -0,0 +1,103 @@
<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="theme/c%2B%2Bboost.gif">
</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 exported too, but you can't export the &quot;Template&quot;
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>&lt;</span><span class=keyword>class </span><span class=identifier>T</span><span class=special>&gt;
</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>&quot;Point&quot;</span><span class=special>, </span><span class=string>&quot;point.h&quot;</span><span class=special>)
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>&quot;int&quot;</span><span class=special>)
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>&quot;double&quot;</span><span class=special>)
</span></pre></code>
<p>
Pyste will assign default names for each instantiation. In this example, those
would be &quot;<tt>Point_int</tt>&quot; and &quot;<tt>Point_double</tt>&quot;, 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>&quot;int&quot;</span><span class=special>, </span><span class=string>&quot;IPoint&quot;</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>&quot;double&quot;</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>&quot;DPoint&quot;</span><span class=special>)
</span></pre></code>
<p>
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> class
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>&quot;Point&quot;</span><span class=special>, </span><span class=string>&quot;point.h&quot;</span><span class=special>)
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>&quot;float&quot;</span><span class=special>, </span><span class=string>&quot;FPoint&quot;</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>&quot;X&quot;</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>&quot;Y&quot;</span><span class=special>)
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>&quot;int&quot;</span><span class=special>, </span><span class=string>&quot;IPoint&quot;</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>&quot;double&quot;</span><span class=special>, </span><span class=string>&quot;DPoint&quot;</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>&quot;Point&quot;</span><span class=special>, </span><span class=string>&quot;point.h&quot;</span><span class=special>)
</span><span class=identifier>Point</span><span class=special>(</span><span class=string>&quot;int&quot;</span><span class=special>, </span><span class=string>&quot;IPoint&quot;</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>&quot;double&quot;</span><span class=special>, </span><span class=string>&quot;DPoint&quot;</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>&quot;X&quot;</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>&quot;Y&quot;</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
(&quot;int double&quot; or [&quot;int&quot;, &quot;double&quot;] 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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

View File

@@ -0,0 +1,81 @@
<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="theme/c%2B%2Bboost.gif">
</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 classes and methods, excluding methods and attributes,
and so 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>-&gt;</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>&lt;&lt; </span><span class=string>&quot;value: &quot; </span><span class=special>&lt;&lt; (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special>&lt;&lt; </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>&quot;test::show&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>Enum</span><span class=special>(</span><span class=string>&quot;choice&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</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>
<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 &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

BIN
pyste/doc/theme/alert.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

BIN
pyste/doc/theme/arrow.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

BIN
pyste/doc/theme/bkd.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
pyste/doc/theme/bkd2.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
pyste/doc/theme/bulb.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

BIN
pyste/doc/theme/bullet.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

BIN
pyste/doc/theme/c++boost.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
pyste/doc/theme/l_arr.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

BIN
pyste/doc/theme/l_arr_disabled.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
pyste/doc/theme/note.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

BIN
pyste/doc/theme/r_arr.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

BIN
pyste/doc/theme/r_arr_disabled.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
pyste/doc/theme/smiley.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

170
pyste/doc/theme/style.css vendored Normal file
View File

@@ -0,0 +1,170 @@
body
{
background-image: url(bkd.gif);
background-color: #FFFFFF;
margin: 1em 2em 1em 2em;
}
h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; }
h2 { font: 140% sans-serif; font-weight: bold; text-align: left; }
h3 { font: 120% sans-serif; font-weight: bold; text-align: left; }
h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; }
h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; }
h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; }
pre
{
border-top: gray 1pt solid;
border-right: gray 1pt solid;
border-left: gray 1pt solid;
border-bottom: gray 1pt solid;
padding-top: 2pt;
padding-right: 2pt;
padding-left: 2pt;
padding-bottom: 2pt;
display: block;
font-family: "courier new", courier, mono;
background-color: #eeeeee; font-size: small
}
code
{
font-family: "Courier New", Courier, mono;
font-size: small
}
tt
{
display: inline;
font-family: "Courier New", Courier, mono;
color: #000099;
font-size: small
}
p
{
text-align: justify;
font-family: Georgia, "Times New Roman", Times, serif
}
ul
{
list-style-image: url(bullet.gif);
font-family: Georgia, "Times New Roman", Times, serif
}
ol
{
font-family: Georgia, "Times New Roman", Times, serif
}
a
{
font-weight: bold;
color: #003366;
text-decoration: none;
}
a:hover { color: #8080FF; }
.literal { color: #666666; font-style: italic}
.keyword { color: #000099}
.identifier {}
.comment { font-style: italic; color: #990000}
.special { color: #800040}
.preprocessor { color: #FF0000}
.string { font-style: italic; color: #666666}
.copyright { color: #666666; font-size: small}
.white_bkd { background-color: #FFFFFF}
.dk_grey_bkd { background-color: #999999}
.quotes { color: #666666; font-style: italic; font-weight: bold}
.note_box
{
display: block;
border-top: gray 1pt solid;
border-right: gray 1pt solid;
border-left: gray 1pt solid;
border-bottom: gray 1pt solid;
padding-right: 12pt;
padding-left: 12pt;
padding-bottom: 12pt;
padding-top: 12pt;
font-family: Arial, Helvetica, sans-serif;
background-color: #E2E9EF;
font-size: small; text-align: justify
}
.table_title
{
background-color: #648CCA;
font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF;
font-weight: bold
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
}
.table_cells
{
background-color: #E2E9EF;
font-family: Geneva, Arial, Helvetica, san-serif;
font-size: small
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
}
.toc
{
DISPLAY: block;
background-color: #E2E9EF
font-family: Arial, Helvetica, sans-serif;
border-top: gray 1pt solid;
border-left: gray 1pt solid;
border-bottom: gray 1pt solid;
border-right: gray 1pt solid;
padding-top: 24pt;
padding-right: 24pt;
padding-left: 24pt;
padding-bottom: 24pt;
}
.toc_title
{
background-color: #648CCA;
padding-top: 4px;
padding-right: 4px;
padding-bottom: 4px;
padding-left: 4px;
font-family: Geneva, Arial, Helvetica, san-serif;
color: #FFFFFF;
font-weight: bold
}
.toc_cells
{
background-color: #E2E9EF;
padding-top: 4px;
padding-right: 4px;
padding-bottom: 4px;
padding-left: 4px;
font-family: Geneva, Arial, Helvetica, san-serif;
font-size: small
}
div.logo
{
float: right;
}
.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }

BIN
pyste/doc/theme/u_arr.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

108
pyste/doc/wrappers.html Normal file
View File

@@ -0,0 +1,108 @@
<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_all_declarations_from_a_header.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
<tr>
<td><img src="theme/c%2B%2Bboost.gif">
</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_all_declarations_from_a_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>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt; </span><span class=identifier>names</span><span class=special>();
</span></pre></code>
<p>
But you don't want to export a vector&lt;string&gt;, you want this function to return
a python list of strings. <a href="../../index.html">
Boost.Python</a> has an excellent support for 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>vector</span><span class=special>&lt;</span><span class=identifier>string</span><span class=special>&gt; </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>each </span><span class=identifier>string </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>vector </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>list
</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>&quot;names&quot;</span><span class=special>, &amp;</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, like &quot;<tt>test_wrappers.h</tt>&quot;, and in the interface file:</p>
<code><pre>
<span class=identifier>Include</span><span class=special>(</span><span class=string>&quot;test_wrappers.h&quot;</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>&quot;names&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</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>&quot;names_wrapper&quot;</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>&quot;names_wrapper&quot;</span><span class=special>,
</span><span class=string>&quot;&quot;</span><span class=string>&quot;
list names_wrapper()
{
// call name() and convert the vector to a list...
}
&quot;</span><span class=string>&quot;&quot;</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>&quot;names&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</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 done with methods too. Just remember that the first
parameter of wrappers for methods is a pointer to the class, like in
<a href="../../index.html">
Boost.Python</a>:</p>
<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>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt; </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>-&gt;</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>&quot;C&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</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>&quot;names_wrapper&quot;</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="templates.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<br>
<hr size="1"><p class="copyright">Copyright &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

71
pyste/index.html Normal file
View File

@@ -0,0 +1,71 @@
<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="introduction.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
<tr>
<td><img src="doc/theme/c%2B%2Bboost.gif">
</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_all_declarations_from_a_header.html">Exporting All Declarations from a Header</a>
</td>
</tr>
</table>
<br>
<hr size="1"><p class="copyright">Copyright &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

1
pyste/src/.cvsignore Normal file
View File

@@ -0,0 +1 @@
*.pyc

688
pyste/src/ClassExporter.py Normal file
View File

@@ -0,0 +1,688 @@
import exporters
from Exporter import Exporter
from declarations import *
from enumerate import enumerate
from settings import *
from CodeUnit import CodeUnit
from EnumExporter import EnumExporter
#==============================================================================
# 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['include'] = []
# a list of Method instances
self.methods = []
# a list of Constructor instances
self.constructors = []
# a dict of methodname => _WrapperVirtualMethod instances
self.virtual_wrappers = {}
# a list of code units, generated by nested declarations
self.nested_codeunits = []
def ScopeName(self):
return _ID(self.class_.FullName()) + '_scope'
def Name(self):
return self.class_.FullName()
def SetDeclarations(self, declarations):
Exporter.SetDeclarations(self, declarations)
decl = self.GetDeclaration(self.info.name)
if isinstance(decl, Typedef):
self.class_ = decl.type
if not self.info.rename:
self.info.rename = decl.name
else:
self.class_ = decl
self.public_members = \
[x for x in self.class_.members if x.visibility == Scope.public]
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.
'''
def BasesCount(classname):
decl = self.GetDeclaration(classname)
bases = [x.name for x in decl.bases]
total = 0
for base in bases:
total += BasesCount(base)
return len(bases) + total
return BasesCount(self.class_.FullName())
def Export(self, codeunit, exported_names):
self.GetMethods()
self.ExportBasics()
self.ExportBases(exported_names)
self.ExportConstructors()
self.ExportVariables()
self.ExportMethods()
self.GenerateVirtualWrapper()
self.ExportOperators()
self.ExportNestedClasses(exported_names)
self.ExportNestedEnums()
self.Write(codeunit)
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')
# 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.strip())
def ExportBasics(self):
'Export the name of the class and its class_ statement'
self.Add('template', self.class_.FullName())
name = self.info.rename or self.class_.name
self.Add('constructor', '"%s"' % name)
def ExportBases(self, exported_names):
'Expose the bases of the class into the template section'
bases = self.class_.bases
bases_list = []
for base in bases:
if base.visibility == Scope.public and base.name in exported_names:
bases_list.append(base.name)
if bases_list:
code = namespaces.python + 'bases< %s > ' % \
(', '.join(bases_list))
self.Add('template', code)
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)]
self.constructors = constructors[:]
if not constructors:
# declare no_init
self.Add('constructor', py_ns + 'no_init')
else:
# write one of the constructors to the class_ constructor
self.Add('constructor', init_code(constructors.pop(0)))
# 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.static:
code = '%s->attr("%s") = %s;' % (self.ScopeName(), name, fullname)
self.Add('scope', code)
else:
if var.type.const:
def_ = '.def_readonly'
else:
def_ = '.def_readwrite'
code = '%s("%s", &%s)' % (def_, name, fullname)
self.Add('inside', code)
def GetMethods(self):
'fill self.methods with a list of Method instances'
# get a list of all methods
def IsValid(m):
'Returns true if the given method is exportable by this routine'
ignore = (Constructor, ClassOperator, Destructor)
return isinstance(m, Method) and not isinstance(m, ignore)
self.methods = [x for x in self.public_members if IsValid(x)]
printed_policy_warnings = {}
def CheckPolicy(self, m):
'Warns the user if this method needs a policy'
def IsString(type):
return type.const and type.name == 'char' and isinstance(type, PointerType)
needs_policy = isinstance(m.result, (ReferenceType, PointerType))
if IsString(m.result):
needs_policy = False
has_policy = self.info[m.name].policy is not None
if needs_policy and not has_policy:
warning = '---> Error: Method "%s" needs a policy.' % m.FullName()
if warning not in self.printed_policy_warnings:
print warning
print
self.printed_policy_warnings[warning] = 1
def ExportMethods(self):
'Export all the methods of the class'
def OverloadName(m):
'Returns the name of the overloads struct for the given method'
return _ID(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
declared = {}
def DeclareOverloads(m):
'Declares the macro for the generation of the overloads'
if m.virtual:
func = self.virtual_wrappers[m.PointerDeclaration()].DefaultName()
else:
func = m.name
code = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(%s, %s, %i, %i)\n'
code = code % (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[method.name].wrapper
if wrapper:
return '&' + wrapper.FullName()
# if this method is virtual, return the pointers to the class and its wrapper
if m.virtual:
return self.virtual_wrappers[m.PointerDeclaration()].Pointer()
# return normal pointers to the methods of the class
is_unique = self.class_.IsUnique(m.name)
if is_unique:
return '&' + method.FullName()
else:
return method.PointerDeclaration()
for method in self.methods:
if self.info[method.name].exclude:
continue # skip this method
name = self.info[method.name].rename or method.name
# check if this method needs to be wrapped as a virtual method
if method.virtual:
wrapper = _WrapperVirtualMethod(self.class_, method, name)
self.virtual_wrappers[method.PointerDeclaration()] = wrapper
# abstract methods don't need to be exported
if method.abstract:
continue # skip .def declaration for abstract methods
# warn the user if this method needs a policy and doesn't have one
self.CheckPolicy(method)
# check for policies
policy = self.info[method.name].policy or ''
if policy:
policy = ', %s%s()' % (namespaces.python, policy.Code())
# check for overloads
overload = ''
if method.minArgs != method.maxArgs:
# add the overloads for this method
overload_name = OverloadName(method)
DeclareOverloads(method)
if not method.virtual:
overload = ', %s%s()' % (namespaces.pyste, overload_name)
else:
pyste_ns = namespaces.pyste
pointer = self.virtual_wrappers[method.PointerDeclaration()].DefaultPointer()
defcode = '.def("%s", %s, %s%s())' % \
(name, pointer, pyste_ns, overload_name)
self.Add('inside', defcode)
# build the 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 method.static:
code = '.staticmethod("%s")' % name
self.Add('inside', code)
# add wrapper code if this method has one
wrapper = self.info[method.name].wrapper
if wrapper and wrapper.code:
self.Add('declaration', wrapper.code)
def GenerateVirtualWrapper(self):
'Generate the wrapper to dispatch virtual methods'
# check if this class needs a wrapper first
for m in self.methods:
if m.virtual:
break
else:
return
# add the wrapper name to the template section
wrapper_name = _WrapperName(self.class_)
self.Add('template', namespaces.pyste + wrapper_name)
indent = self.INDENT
method_codes = [x.Code(indent) for x in self.virtual_wrappers.values()]
body = '\n'.join(method_codes)
# generate the class code
class_name = self.class_.FullName()
code = 'struct %s: %s\n' % (wrapper_name, class_name)
code += '{\n'
# generate constructors
for cons in self.constructors:
params, param_names, param_types = _ParamsInfo(cons)
if params:
params = ', ' + params
cons_code = indent + '%s(PyObject* self_%s):\n' % (wrapper_name, params)
cons_code += indent*2 + '%s(%s), self(self_) {}\n\n' % \
(class_name, ', '.join(param_names))
code += cons_code
code += body + '\n'
code += indent + 'PyObject* self;\n'
code += '};\n'
self.Add('declaration', code)
# 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 signature
BOOST_RENAME_OPERATORS = {
'()' : '__call__',
}
# converters which has a special name in python
SPECIAL_CONVETERS = {
'double' : '__float__',
'float' : '__float__',
'int' : '__int__',
}
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', wrapper.code)
elif isinstance(operator, ClassOperator) and self.class_.IsUnique(operator.name):
pointer = '&' + operator.FullName()
else:
pointer = operator.PointerDeclaration()
rename = self.info['operator'][operator.name].rename
# 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.name
# extract the last name from the full name
result_name = _ID(result_fullname.split('::')[-1])
return 'to_' + result_name
for converter in converters:
info = self.info['operator'][converter.result.name]
# 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)
if self.class_.IsUnique(converter.name):
pointer = '&' + converter.FullName()
else:
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 = ClassExporter(nested_info)
exporter.SetDeclarations(self.declarations + [nested_class])
codeunit = CodeUnit(None)
exporter.Export(codeunit, exported_names)
self.nested_codeunits.append(codeunit)
def ExportNestedEnums(self):
nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
for enum in nested_enums:
enum_info = self.info[enum.name]
enum_info.include = self.info.include
enum_info.name = enum.FullName()
exporter = EnumExporter(enum_info)
exporter.SetDeclarations(self.declarations + [enum])
codeunit = CodeUnit(None)
exporter.Export(codeunit, None)
self.nested_codeunits.append(codeunit)
def _ID(name):
'Returns the name as a valid identifier'
for invalidchar in ('::', '<', '>', ' ', ','):
name = name.replace(invalidchar, '_')
# avoid duplications of '_' chars
names = [x for x in name.split('_') if x]
return '_'.join(names)
#==============================================================================
# Virtual Wrapper utils
#==============================================================================
def _WrapperName(class_):
return _ID(class_.FullName()) + '_Wrapper'
def _ParamsInfo(m):
param_names = ['p%i' % i for i in range(len(m.parameters))]
param_types = [x.FullName() for x in m.parameters]
params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)]
for i, p in enumerate(m.parameters):
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 _WrapperVirtualMethod(object):
'Holds information about a virtual method that will be wrapped'
def __init__(self, class_, method, rename):
self.method = method
if rename is None:
rename = method.name
self.rename = rename
self.class_ = class_
def DefaultName(self):
return 'default_' + self.method.name
def DefaultPointer(self):
ns = namespaces.pyste
wrapper_name = _WrapperName(self.class_)
default_name = self.DefaultName()
fullname = '%s%s::%s' % (ns, wrapper_name, default_name)
if self.class_.IsUnique(self.method.name):
return '&%s' % fullname
else:
# the method is not unique, so we must specify the entire signature with it
param_list = [x.FullName() for x in self.method.parameters]
params = ', '.join(param_list)
result = self.method.result.FullName()
signature = '%s (%s%s::*)(%s)' % (result, ns, wrapper_name, params)
return '(%s)%s' % (signature, fullname)
def Pointer(self):
'''Returns the "pointer" declaration for this method, ie, the contents
of the .def after the method name (.def("name", <pointer>))'''
ns = namespaces.pyste
default_name = self.DefaultName()
name = self.method.name
class_name = self.class_.FullName()
wrapper = ns + _WrapperName(self.class_)
if self.class_.IsUnique(self.method.name):
return '&%s::%s, &%s::%s' % (class_name, name, wrapper, default_name)
else:
# the method is not unique, so we must specify the entire signature with it
param_list = [x.FullName() for x in self.method.parameters]
params = ', '.join(param_list)
result = self.method.result.FullName()
default_sig = '%s (%s::*)(%s)' % (result, wrapper, params)
normal_sig = '%s (%s::*)(%s)' % (result, class_name, params)
return '(%s)%s::%s, (%s)%s::%s' % \
(normal_sig, class_name, name, default_sig, wrapper, default_name)
def Code(self, indent):
params, param_names, param_types = _ParamsInfo(self.method)
result = self.method.result.FullName()
return_ = 'return '
if result == 'void':
return_ = ''
param_names = ', '.join(param_names)
class_name = self.class_.FullName()
method_name = self.method.name
default_name = self.DefaultName()
# constantness
const = ''
if self.method.const:
const = 'const '
code = ''
# create default_method if this method has a default implementation
if not self.method.abstract:
default_sig = '%s %s(%s) %s' % (result, default_name, params, const)
body = '{ %s%s::%s(%s); } ' % \
(return_, class_name, method_name, param_names)
code += indent + default_sig + body + '\n'
# create normal method
normal_sig = '%s %s(%s) %s' % (result, method_name, params, const)
if param_names:
param_names = ', ' + param_names
body = '{ %s%scall_method< %s >(self, "%s"%s); }' % \
(return_, namespaces.python, result, self.rename, param_names)
code += indent + normal_sig + body + '\n'
return code

78
pyste/src/CodeUnit.py Normal file
View File

@@ -0,0 +1,78 @@
from settings import *
#==============================================================================
# RemoveDuplicatedLines
#==============================================================================
def RemoveDuplicatedLines(text):
includes = text.splitlines()
d = dict([(include, 0) for include in includes])
return '\n'.join(d.keys())
#==============================================================================
# CodeUnit
#==============================================================================
class CodeUnit:
'''
Represents a cpp file, where other objects can write in one of the
predefined sections.
The avaiable sections are:
include - The include area of the cpp file
declaration - The part before the module definition
module - Inside the BOOST_PYTHON_MODULE macro
'''
USING_BOOST_NS = True
def __init__(self, modulename):
self.modulename = modulename
# define the avaiable sections
self.code = {}
self.code['include'] = ''
self.code['declaration'] = ''
self.code['module'] = ''
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 Section(self, section):
return self.code[section]
def Save(self, filename):
'Writes this code unit to the filename'
space = '\n\n'
fout = file(filename, 'w')
# includes
includes = RemoveDuplicatedLines(self.code['include'])
fout.write('\n' + self._leftEquals('Includes'))
fout.write('#include <boost/python.hpp>\n')
fout.write(includes)
fout.write(space)
# using
if self.USING_BOOST_NS:
fout.write(self._leftEquals('Using'))
fout.write('using namespace boost::python;\n\n')
# declarations
if self.code['declaration']:
pyste_namespace = namespaces.pyste[:-2]
fout.write(self._leftEquals('Declarations'))
fout.write('namespace %s {\n\n\n' % pyste_namespace)
fout.write(self.code['declaration'])
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
fout.write(space)
# module
fout.write(self._leftEquals('Module'))
fout.write('BOOST_PYTHON_MODULE(%s)\n{\n' % self.modulename)
fout.write(self.code['module'])
fout.write('}\n')
def _leftEquals(self, s):
s = '// %s ' % s
return s + ('='*(80-len(s))) + '\n'

94
pyste/src/CppParser.py Normal file
View File

@@ -0,0 +1,94 @@
from GCCXMLParser import ParseDeclarations
import tempfile
import shutil
import os
import os.path
import settings
class CppParserError(Exception): pass
class CppParser:
'Parses a header file and returns a list of declarations'
def __init__(self, includes=None, defines=None):
'includes and defines ar the directives given to gcc'
if includes is None:
includes = []
if defines is None:
defines = []
self.includes = includes
self.defines = defines
def _includeparams(self, filename):
includes = self.includes[:]
filedir = os.path.dirname(filename)
if not filedir:
filedir = '.'
includes.insert(0, filedir)
includes = ['-I "%s"' % x for x in includes]
return ' '.join(includes)
def _defineparams(self):
defines = ['-D "%s"' % x for x in self.defines]
return ' '.join(defines)
def FindFileName(self, include):
if os.path.isfile(include):
return include
for path in self.includes:
filename = os.path.join(path, include)
if os.path.isfile(filename):
return filename
name = os.path.basename(include)
raise RuntimeError, 'Header file "%s" not found!' % name
def parse(self, include, symbols=None, tail=None):
'''Parses the given filename, and returns (declaration, header). The
header returned is normally the same as the given to this method,
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 gcc.
This temp filename is then returned.
'''
filename = self.FindFileName(include)
# copy file to temp folder, if needed
if tail:
tempfilename = tempfile.mktemp('.h')
infilename = tempfilename
shutil.copy(filename, infilename)
f = file(infilename, 'a')
f.write('\n\n'+tail)
f.close()
else:
infilename = filename
xmlfile = tempfile.mktemp('.xml')
try:
# get the params
includes = self._includeparams(filename)
defines = self._defineparams()
# call gccxml
cmd = 'gccxml %s %s %s -fxml=%s' \
% (includes, defines, infilename, xmlfile)
if symbols:
cmd += ' -fxml-start=' + ','.join(symbols)
status = os.system(cmd)
if status != 0 or not os.path.isfile(xmlfile):
raise CppParserError, 'Error executing gccxml'
# parse the resulting xml
declarations = ParseDeclarations(xmlfile)
# return the declarations
return declarations, infilename
finally:
if settings.DEBUG and os.path.isfile(xmlfile):
filename = os.path.basename(include)
shutil.copy(xmlfile, os.path.splitext(filename)[0] + '.xml')
# delete the temporary files
try:
os.remove(xmlfile)
if tail:
os.remove(tempfilename)
except OSError: pass

30
pyste/src/EnumExporter.py Normal file
View File

@@ -0,0 +1,30 @@
from Exporter import Exporter
from settings import *
#==============================================================================
# EnumExporter
#==============================================================================
class EnumExporter(Exporter):
'Exports enumerators'
def __init__(self, info):
Exporter.__init__(self, info)
def SetDeclarations(self, declarations):
Exporter.SetDeclarations(self, declarations)
self.enum = self.GetDeclaration(self.info.name)
def Export(self, codeunit, expoted_names):
indent = self.INDENT
in_indent = self.INDENT*2
rename = self.info.rename or self.enum.name
full_name = self.enum.FullName()
code = indent + namespaces.python + '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)
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
code += indent + ';\n\n'
codeunit.Write('module', code)

69
pyste/src/Exporter.py Normal file
View File

@@ -0,0 +1,69 @@
import os.path
#==============================================================================
# Exporter
#==============================================================================
class Exporter:
'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
def Parse(self, parser):
self.parser = parser
header = self.info.include
tail = self.parser_tail
declarations, parser_header = parser.parse(header, tail=tail)
self.parser_header = parser_header
self.SetDeclarations(declarations)
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 Name(self):
'''Returns the name of this Exporter. The name will be added to the
list of names exported, which may have a use for other exporters.
'''
return None
def GetDeclarations(self, fullname):
decls = [x for x in self.declarations if x.FullName() == fullname]
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 number that indicates to which order this exporter
belongs. The exporters will be called from the lowest order to the
highest order.
This function will only be called after Parse has been called.
'''
return None # don't care

View File

@@ -0,0 +1,81 @@
from Exporter import Exporter
from policies import *
from declarations import *
from settings import *
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):
decls = self.GetDeclarations(self.info.name)
for decl in decls:
self.CheckPolicy(decl)
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
self.GenerateOverloads(decls, codeunit)
def Name(self):
return self.info.name
def CheckPolicy(self, func):
'Warns the user if this function needs a policy'
needs_policy = isinstance(func.result, (ReferenceType, PointerType))
if needs_policy and self.info.policy is None:
print '---> Error: Function "%s" needs a policy.' % func.FullName()
print
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()
elif not unique:
pointer = decl.PointerDeclaration()
else:
pointer = '&' + decl.FullName()
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', 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 ''

395
pyste/src/GCCXMLParser.py Normal file
View File

@@ -0,0 +1,395 @@
from declarations import *
from elementtree.ElementTree import ElementTree
from xml.parsers.expat import ExpatError
from copy import deepcopy
class InvalidXMLError(Exception): pass
class ParserError(Exception): pass
class InvalidContextError(ParserError): pass
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 = []
# 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):
self.declarations.append(decl)
def ParseElement(self, id, element):
method = 'Parse' + element.tag
if hasattr(self, method):
func = getattr(self, method)
func(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):
const = False
volatile = False
if id[-1] == 'v':
volatile = True
id = id[:-1]
if id[-1] == 'c':
const = True
id = id[:-1]
decl = self.GetDecl(id)
if isinstance(decl, Type):
res = deepcopy(decl)
if const:
res.const = const
if volatile:
res.volatile = volatile
else:
res = Type(decl.FullName(), const)
res.volatile = volatile
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 ParseNamespace(self, id, element):
namespace = element.get('name')
context = element.get('context')
if context:
outerns = self.GetDecl(context)
if not outerns.endswith('::'):
outerns += '::'
namespace = outerns + 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 if apply.
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 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)
function = functionType(name, namespace, returns, params)
function.location = location
self.AddDecl(function)
self.Update(id, function)
def ParseOperatorFunction(self, id, element):
self.ParseFunction(id, element, Operator)
def GetBases(self, bases):
'Parses the string "bases" from the xml into a list of Base instances.'
if bases is None:
return []
bases = bases.split()
baseobjs = []
for base in bases:
# get the visibility
split = base.split(':')
if len(split) == 2:
visib = split[0]
base = split[1]
else:
visib = Scope.public
decl = self.GetDecl(base)
baseobj = Base(decl.FullName(), visib)
baseobjs.append(baseobj)
return baseobjs
def GetMembers(self, members):
# members must be a string with the ids of the members
if members is None:
return []
memberobjs = []
for member in members.split():
memberobjs.append(self.GetDecl(member))
return memberobjs
def ParseClass(self, id, element):
name = element.get('name')
abstract = bool(int(element.get('abstract', '0')))
bases = self.GetBases(element.get('bases'))
location = self.GetLocation(element.get('location'))
context = self.GetDecl(element.get('context'))
if isinstance(context, Class): # a nested class
visib = element.get('access', Scope.public)
class_ = NestedClass(
name, context.FullName(), visib, [], abstract, bases)
else:
assert isinstance(context, str)
class_ = Class(name, context, [], abstract, bases)
self.AddDecl(class_)
# we have to add the declaration of the class before trying
# to parse its members, to avoid recursion.
class_.location = location
self.Update(id, class_)
# now we can get the members
class_.members = self.GetMembers(element.get('members'))
def ParseStruct(self, id, element):
self.ParseClass(id, element)
def ParseFundamentalType(self, id, element):
name = element.get('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')
if min:
min = int(min)
if max:
max = int(max)
array = ArrayType(type_.name, min, max, type_.const)
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)
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)
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'))
params = self.GetArguments(element)
method = methodType(
name, classname, result, params, visib, virtual, abstract, static, const)
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)
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.GetDecl(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'))
if isinstance(context, Class):
visib = element.get('access', Scope.public)
enum = ClassEnumeration(name, context.FullName(), visib)
else:
enum = Enumeration(name, context)
self.AddDecl(enum) # in this case, is a top level decl
enum.location = location
for child in element:
if child.tag == 'EnumValue':
name = child.get('name')
value = int(child.get('init'))
enum.values[name] = value
self.Update(id, enum)
def ParseUnimplemented(self, id, element):
'No idea of what this is'
self.Update(id, Declaration('', ''))
def ParseUnion(self, id, element):
self.Update(id, Declaration(element.get('name'), ''))
def ParseDeclarations(filename):
'Returns a list of the top declarations found in the gcc_xml file.'
parser = GCCXMLParser()
parser.Parse(filename)
return parser.Declarations()

View File

@@ -0,0 +1,67 @@
from Exporter import Exporter
from ClassExporter import ClassExporter
from FunctionExporter import FunctionExporter
from EnumExporter import EnumExporter
from infos import *
from declarations import *
import os.path
import exporters
#==============================================================================
# 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 SetDeclarations(self, declarations):
def IsInternalName(name):
'''Returns true if the given name looks like a internal compiler
structure'''
return name.startswith('__')
Exporter.SetDeclarations(self, declarations)
header = os.path.normpath(self.parser_header)
for decl in declarations:
# check if this declaration is in the header
location = os.path.normpath(decl.location[0])
if location != header or IsInternalName(decl.name):
continue
# ok, check the type of the declaration and export it accordingly
self.HandleDeclaration(decl)
def HandleDeclaration(self, decl):
'''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,
}
for decl_type, exporter_type in dispatch_table.items():
if type(decl) == decl_type:
self.HandleExporter(decl, exporter_type)
break
def HandleExporter(self, decl, exporter_type):
info = self.info[decl.name]
info.name = decl.FullName()
info.include = self.info.include
exporter = exporter_type(info)
exporter.SetDeclarations(self.declarations)
exporters.exporters.append(exporter)

View File

@@ -0,0 +1,19 @@
import os.path
from Exporter import Exporter
#==============================================================================
# IncludeExporter
#==============================================================================
class IncludeExporter(Exporter):
'''Writes an include declaration to the module. Useful to add extra code
for use in the Wrappers.
This class just reimplements the Parse method to do nothing: the
WriteInclude in Exporter already does the work for us.
'''
def __init__(self, info, parser_tail=None):
Exporter.__init__(self, info, parser_tail)
def Parse(self, parser):
pass

452
pyste/src/declarations.py Normal file
View File

@@ -0,0 +1,452 @@
'''
Module declarations
Defines classes that represent declarations found in C++ header files.
'''
class Declaration(object):
'Represents a basic declaration.'
def __init__(self, name, namespace):
# the declaration name
self.name = name
# all the namespaces, separated by '::' = 'boost::inner'
self.namespace = namespace
# tuple (filename, line)
self.location = '', -1
def FullName(self):
'Returns the full qualified name: "boost::inner::Test"'
namespace = self.namespace or ''
#if not namespace:
# namespace = ''
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(Declaration):
'The declaration of a class or struct.'
def __init__(self, name, namespace, members, abstract, bases):
Declaration.__init__(self, name, namespace)
# list of members
self.members = members
# whatever the class has any abstract methods
self.abstract = abstract
# instances of Base
self.bases = bases
self._members_count = {}
def __iter__(self):
return iter(self.members)
def IsAbstract(self):
'Returns True if any method of this class is abstract'
for member in self.members:
if isinstance(member, Method):
if member.abstract:
return True
return False
def RawName(self):
'Returns the raw name of a template class. name = Foo<int>, raw = Foo'
lesspos = self.name.find('<')
if lesspos != -1:
return self.name[:lesspos]
else:
return self.name
def Constructors(self, publics_only=True):
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):
for cons in self.Constructors():
if cons.IsCopy():
return True
return False
def HasDefaultConstructor(self):
for cons in self.Constructors():
if cons.IsDefault():
return True
return False
def IsUnique(self, member_name):
if not self._members_count:
for m in self:
self._members_count[m.name] = self._members_count.get(m.name, 0) + 1
try:
return self._members_count[member_name] == 1
except KeyError:
print self._members_count
print 'Key', member_name
class NestedClass(Class):
'The declaration of a class/struct inside another class/struct.'
def __init__(self, name, class_, visib, members, abstract, bases):
Class.__init__(self, name, None, members, abstract, bases)
self.class_ = class_
self.visibility = visib
def FullName(self):
return '%s::%s' % (self.class_, self.name)
class Base:
'Represents a base class of another class.'
def __init__(self, name, visibility=None):
# class_ is the full name of the base class
self.name = name
# visibility of the derivation
if visibility is None:
visibility = Scope.public
self.visibility = visibility
class Scope:
public = 'public'
private = 'private'
protected = 'protected'
class Function(Declaration):
'The declaration of a function.'
def __init__(self, name, namespace, result, params):
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
def PointerDeclaration(self):
'returns a declaration of a pointer to this function'
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
return '(%s (*)(%s))%s' % (result, params, self.FullName())
def _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)
class Operator(Function):
'The declaration of a custom operator.'
def FullName(self):
namespace = self.namespace or ''
if not namespace.endswith('::'):
namespace += '::'
return namespace + 'operator' + self.name
class Method(Function):
'The declaration of a method.'
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
Function.__init__(self, name, None, result, params)
self.visibility = visib
self.virtual = virtual
self.abstract = abstract
self.static = static
self.class_ = class_
self.const = const
def FullName(self):
return self.class_ + '::' + self.name
def PointerDeclaration(self):
'returns a declaration of a pointer to this function'
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
const = ''
if self.const:
const = 'const'
return '(%s (%s::*)(%s) %s)%s' %\
(result, self.class_, params, const, self.FullName())
class Constructor(Method):
'A constructor of a class.'
def __init__(self, name, class_, params, visib):
Method.__init__(self, name, class_, None, params, visib, False, False, False, False)
def IsDefault(self):
return len(self.parameters) == 0
def IsCopy(self):
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)
return param_reference and class_as_param and param.const
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
class ClassOperator(Method):
'The declaration of a custom operator in a class.'
def FullName(self):
return self.class_ + '::operator ' + self.name
class ConverterOperator(ClassOperator):
'An operator in the form "operator OtherClass()".'
def FullName(self):
return self.class_ + '::operator ' + self.result.name
class Type(Declaration):
'Represents a type.'
def __init__(self, name, const=False, default=None):
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
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
class ArrayType(Type):
'Represents an array.'
def __init__(self, name, min, max, const=False):
'min and max can be None.'
Type.__init__(self, name, const)
self.min = min
self.max = max
class ReferenceType(Type):
'A reference type.'
def __init__(self, name, const=False, default=None, expandRef=True):
Type.__init__(self, name, const, default)
self.expand = expandRef
def FullName(self):
'expand is False for function pointers'
expand = ' &'
if not self.expand:
expand = ''
return Type.FullName(self) + expand
class PointerType(Type):
'A pointer type.'
def __init__(self, name, const=False, default=None, expandPointer=False):
Type.__init__(self, name, const, default)
self.expand = expandPointer
def FullName(self):
'expand is False for function pointer'
expand = ' *'
if not self.expand:
expand = ''
return Type.FullName(self) + expand
class FundamentalType(Type):
'One of the fundamental types (int, void...).'
def __init__(self, name, const=False):
Type.__init__(self, name, const)
class FunctionType(Type):
'A pointer to a function.'
def __init__(self, result, params):
Type.__init__(self, '', False)
self.result = result
self.parameters = params
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
class MethodType(FunctionType):
'A pointer to a member function of a class.'
def __init__(self, result, params, class_):
Type.__init__(self, '', False)
self.result = result
self.parameters = params
self.class_ = class_
self.name = self.FullName()
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
class Variable(Declaration):
'Represents a global variable.'
def __init__(self, type, name, namespace):
Declaration.__init__(self, name, namespace)
# instance of Type
self.type = type
class ClassVariable(Variable):
'Represents a class variable.'
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
class Enumeration(Declaration):
def __init__(self, name, namespace):
Declaration.__init__(self, name, namespace)
self.values = {} # dict of str => int
def ValueFullName(self, name):
assert name in self.values
namespace = self.namespace
if namespace:
namespace += '::'
return namespace + name
class ClassEnumeration(Enumeration):
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)
class Typedef(Declaration):
def __init__(self, type, name, namespace):
Declaration.__init__(self, name, namespace)
self.type = type
self.visibility = Scope.public

7
pyste/src/enumerate.py Normal file
View File

@@ -0,0 +1,7 @@
from __future__ import generators
def enumerate(seq):
i = 0
for x in seq:
yield i, x
i += 1

3
pyste/src/exporters.py Normal file
View File

@@ -0,0 +1,3 @@
# a list of Exporter instances
exporters = []

View File

@@ -0,0 +1,26 @@
'''
Various helpers for interface files.
'''
from settings import *
#==============================================================================
# FunctionWrapper
#==============================================================================
class FunctionWrapper(object):
'''Holds information about a wrapper for a function or a method. It is 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

185
pyste/src/infos.py Normal file
View File

@@ -0,0 +1,185 @@
import os.path
import copy
import exporters
from ClassExporter import ClassExporter
from FunctionExporter import FunctionExporter
from IncludeExporter import IncludeExporter
from EnumExporter import EnumExporter
from HeaderExporter import HeaderExporter
from exporterutils import FunctionWrapper
#==============================================================================
# DeclarationInfo
#==============================================================================
class DeclarationInfo(object):
def __init__(self, otherInfo=None):
self.__infos = {}
self.__attributes = {}
if otherInfo is not None:
self.__infos = otherInfo.__infos.copy()
self.__attributes = otherInfo.__attributes.copy()
def __getitem__(self, name):
'Used to access sub-infos'
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
#==============================================================================
# FunctionInfo
#==============================================================================
class FunctionInfo(DeclarationInfo):
def __init__(self, name, include, tail=None, otherOption=None):
DeclarationInfo.__init__(self, otherOption)
self._Attribute('name', name)
self._Attribute('include', include)
# create a FunctionExporter
exporter = FunctionExporter(InfoWrapper(self), tail)
exporters.exporters.append(exporter)
#==============================================================================
# ClassInfo
#==============================================================================
class ClassInfo(DeclarationInfo):
def __init__(self, name, include, tail=None, otherOption=None):
DeclarationInfo.__init__(self, otherOption)
self._Attribute('name', name)
self._Attribute('include', include)
# create a ClassExporter
exporter = ClassExporter(InfoWrapper(self), tail)
exporters.exporters.append(exporter)
#==============================================================================
# IncludeInfo
#==============================================================================
class IncludeInfo(DeclarationInfo):
def __init__(self, include):
DeclarationInfo.__init__(self)
self._Attribute('include', include)
exporter = IncludeExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
#==============================================================================
# templates
#==============================================================================
def GenerateName(name, type_list):
name = name.replace('::', '_')
names = [name] + type_list
return '_'.join(names)
class ClassTemplateInfo(DeclarationInfo):
def __init__(self, name, include):
DeclarationInfo.__init__(self)
self._Attribute('name', name)
self._Attribute('include', include)
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)
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):
DeclarationInfo.__init__(self)
self._Attribute('name', name)
self._Attribute('include', include)
exporter = EnumExporter(InfoWrapper(self))
exporters.exporters.append(exporter)
#==============================================================================
# HeaderInfo
#==============================================================================
class HeaderInfo(DeclarationInfo):
def __init__(self, include):
DeclarationInfo.__init__(self)
self._Attribute('include', include)
exporter = HeaderExporter(InfoWrapper(self))
exporters.exporters.append(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(option):
option._Attribute('exclude', True)
def set_policy(option, policy):
option._Attribute('policy', policy)
def rename(option, name):
option._Attribute('rename', name)
def set_wrapper(option, wrapper):
if isinstance(wrapper, str):
wrapper = FunctionWrapper(wrapper)
option._Attribute('wrapper', wrapper)
def instantiate(template, types, rename=None):
if isinstance(types, str):
types = types.split()
return template.Instantiate(types, rename)

75
pyste/src/policies.py Normal file
View File

@@ -0,0 +1,75 @@
class Policy:
'Represents one of the call policies of boost.python.'
def __init__(self):
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 ' >'
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
# 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'

View File

@@ -0,0 +1,17 @@
import profile
import pstats
import pyste
import psyco
import elementtree.XMLTreeBuilder as XMLTreeBuilder
import GCCXMLParser
if __name__ == '__main__':
#psyco.bind(XMLTreeBuilder.fixtext)
#psyco.bind(XMLTreeBuilder.fixname)
#psyco.bind(XMLTreeBuilder.TreeBuilder)
#psyco.bind(GCCXMLParser.GCCXMLParser)
profile.run('pyste.Main()', 'profile')
p = pstats.Stats('profile')
p.strip_dirs().sort_stats(-1).print_stats()

154
pyste/src/pyste.py Normal file
View File

@@ -0,0 +1,154 @@
'''
Usage:
pyste [options] --module=<name> interface-files
where options are:
-I <path> add an include path
-D <symbol> define symbol
--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 "pyste"
'''
import sys
import os
import getopt
import exporters
import CodeUnit
import infos
import exporterutils
import settings
from policies import *
from CppParser import CppParser, CppParserError
from Exporter import Exporter
from FunctionExporter import FunctionExporter
from ClassExporter import ClassExporter
from IncludeExporter import IncludeExporter
from HeaderExporter import HeaderExporter
def GetDefaultIncludes():
if 'INCLUDE' in os.environ:
include = os.environ['INCLUDE']
return include.split(os.pathsep)
else:
return []
def ParseArguments():
def Usage():
print __doc__
sys.exit(1)
options, files = getopt.getopt(sys.argv[1:], 'I:D:', ['module=', 'out=', 'no-using', 'pyste-ns=', 'debug'])
includes = GetDefaultIncludes()
defines = []
module = None
out = None
for opt, value in options:
if opt == '-I':
includes.append(value)
elif opt == '-D':
defines.append(value)
elif opt == '--module':
module = value
elif opt == '--out':
out = value
elif opt == '--no-using':
settings.namespaces.python = 'boost::python::'
CodeUnit.CodeUnit.USING_BOOST_NS = False
elif opt == '--pyste-ns':
settings.namespaces.pyste = value + '::'
elif opt == '--debug':
settings.DEBUG = True
else:
print 'Unknown option:', opt
Usage()
if not files or not module:
Usage()
if not out:
out = module + '.cpp'
return includes, defines, module, out, files
def CreateContext():
'create the context where a interface file can be executed'
context = {}
# infos
context['Function'] = infos.FunctionInfo
context['Class'] = infos.ClassInfo
context['Include'] = infos.IncludeInfo
context['Template'] = infos.ClassTemplateInfo
context['Enum'] = infos.EnumInfo
context['AllFromHeader'] = infos.HeaderInfo
# functions
context['rename'] = infos.rename
context['set_policy'] = infos.set_policy
context['exclude'] = infos.exclude
context['set_wrapper'] = infos.set_wrapper
# 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['manage_new_object'] = manage_new_object
# utils
context['Wrapper'] = exporterutils.FunctionWrapper
return context
def Main():
includes, defines, module, out, interfaces = ParseArguments()
# execute the interface files
for interface in interfaces:
context = CreateContext()
execfile(interface, context)
# parse all the C++ code
parser = CppParser(includes, defines)
exports = exporters.exporters[:]
for export in exports:
try:
export.Parse(parser)
except CppParserError, e:
print '\n'
print '***', e, ': exitting'
return 2
print
# sort the exporters by its order
exports = [(x.Order(), x) for x in exporters.exporters]
exports.sort()
exports = [x for _, x in exports]
# now generate the wrapper code
codeunit = CodeUnit.CodeUnit(module)
exported_names = []
for export in exports:
export.GenerateCode(codeunit, exported_names)
exported_names.append(export.Name())
codeunit.Save(out)
print 'Module %s generated' % module
return 0
def UsePsyco():
'Tries to use psyco if it is installed'
try:
import psyco
import elementtree.XMLTreeBuilder as XMLTreeBuilder
import GCCXMLParser
psyco.bind(XMLTreeBuilder.fixtext)
psyco.bind(XMLTreeBuilder.fixname)
psyco.bind(XMLTreeBuilder.TreeBuilder)
psyco.bind(GCCXMLParser.GCCXMLParser)
except ImportError: pass
if __name__ == '__main__':
UsePsyco()
status = Main()
sys.exit(status)

12
pyste/src/settings.py Normal file
View File

@@ -0,0 +1,12 @@
#==============================================================================
# Global information
#==============================================================================
DEBUG = False
class namespaces:
boost = 'boost::'
pyste = ''
python = '' # default is to not use boost::python namespace explicitly, so
# use the "using namespace" statement instead

View File

@@ -0,0 +1,338 @@
import sys
sys.path.append('..')
import unittest
import tempfile
import os.path
import GCCXMLParser
from 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)
self.assertEqual(self.base.RawName(), 'Base')
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(), '(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(),
'(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>')
self.assertEqual(self.template.RawName(), 'Template')
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(),
'(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()

50
pyste/tests/infosUT.py Normal file
View File

@@ -0,0 +1,50 @@
import sys
sys.path.append('../src')
from infos import *
from policies import *
from exporterutils import *
import unittest
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()

59
pyste/tests/policiesUT.py Normal file
View File

@@ -0,0 +1,59 @@
import sys
sys.path.append('..')
import unittest
from policies import *
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')
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()

14
pyste/tests/runtests.py Normal file
View File

@@ -0,0 +1,14 @@
import sys
sys.path.append('../src')
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()
runner.run(unittest.TestSuite(tests))