mirror of
https://github.com/boostorg/python.git
synced 2026-01-20 16:52:15 +00:00
Compare commits
119 Commits
boost-0.9.
...
boost-0.9.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1a1e3be8a | ||
|
|
929badf4c6 | ||
|
|
c4a3f2c04f | ||
|
|
a933e458b3 | ||
|
|
06b8320815 | ||
|
|
7f3aceafd2 | ||
|
|
da5979931c | ||
|
|
d8c7e75095 | ||
|
|
187506c97f | ||
|
|
145c6d1e4f | ||
|
|
e2973f27f9 | ||
|
|
976b8180ae | ||
|
|
37acf41d43 | ||
|
|
6f26778491 | ||
|
|
834d815c87 | ||
|
|
57e58c445b | ||
|
|
8a1a8342d6 | ||
|
|
fa70ddc2c5 | ||
|
|
8ca32bb494 | ||
|
|
f6c82eba0c | ||
|
|
344044a315 | ||
|
|
b10805dc4c | ||
|
|
07f397e2ed | ||
|
|
054dc439d2 | ||
|
|
5008dcbdd4 | ||
|
|
9c6650963f | ||
|
|
d482d57689 | ||
|
|
edf6516085 | ||
|
|
957ac66e14 | ||
|
|
07ce84c4e7 | ||
|
|
918636ff03 | ||
|
|
83a6adbfa9 | ||
|
|
fcbc1d562f | ||
|
|
c3b4b58075 | ||
|
|
568b62a8a4 | ||
|
|
da34e7f507 | ||
|
|
a0c31b47e5 | ||
|
|
5fb677c0c5 | ||
|
|
168476382a | ||
|
|
7fa6a29814 | ||
|
|
f2b51da0ab | ||
|
|
53726746b8 | ||
|
|
fe0b59f559 | ||
|
|
c014dee6dc | ||
|
|
90c69d961e | ||
|
|
342f7db678 | ||
|
|
9eb704f85a | ||
|
|
7754a91929 | ||
|
|
e4dc639e54 | ||
|
|
5d90101671 | ||
|
|
437fb70852 | ||
|
|
d598404c48 | ||
|
|
32c7088600 | ||
|
|
ccede29816 | ||
|
|
b55b7e2f7b | ||
|
|
9217a6a253 | ||
|
|
07c1319b99 | ||
|
|
714b5dc26e | ||
|
|
1f715958f9 | ||
|
|
0922aca873 | ||
|
|
30ec6181b5 | ||
|
|
b28d586612 | ||
|
|
f48aacf477 | ||
|
|
bfa868a440 | ||
|
|
f01ff3a277 | ||
|
|
d88e6bf688 | ||
|
|
a3cdacd088 | ||
|
|
81d99c855f | ||
|
|
5cd110f625 | ||
|
|
416895ff30 | ||
|
|
e41abb6e92 | ||
|
|
a6440a3fa6 | ||
|
|
2dece7ecaf | ||
|
|
7aae525587 | ||
|
|
ac5314093b | ||
|
|
1524fb9fa9 | ||
|
|
957549460b | ||
|
|
3b33f54fb8 | ||
|
|
42ab6b6b66 | ||
|
|
f59a5bbabc | ||
|
|
0be371d747 | ||
|
|
2b52210291 | ||
|
|
96a7bce78e | ||
|
|
c1e1ea697c | ||
|
|
874d6ebf2c | ||
|
|
77f5eb703c | ||
|
|
af53ae8329 | ||
|
|
8f76b8880e | ||
|
|
fa398734be | ||
|
|
362d20a8c7 | ||
|
|
6a33b8aeeb | ||
|
|
d4e06ac436 | ||
|
|
817dcd37e0 | ||
|
|
25bfd3c50f | ||
|
|
b13c902fb0 | ||
|
|
c95ef44b02 | ||
|
|
162727590c | ||
|
|
7e159844fb | ||
|
|
787b79cc2c | ||
|
|
b77652b499 | ||
|
|
0c8444b8ed | ||
|
|
3e6ee799ba | ||
|
|
dd14ccb115 | ||
|
|
ba0fcd27c3 | ||
|
|
d476e67067 | ||
|
|
4588f5e9ab | ||
|
|
68f54d364b | ||
|
|
7dba18e7b9 | ||
|
|
67b265fe96 | ||
|
|
8289269a86 | ||
|
|
9f711ed821 | ||
|
|
73e2ab5125 | ||
|
|
7ea2ab1672 | ||
|
|
c821e903f8 | ||
|
|
54db04521a | ||
|
|
91fdecd76f | ||
|
|
f140a74a13 | ||
|
|
4854a2a81b | ||
|
|
d94bb65006 |
70
pyste/NEWS
70
pyste/NEWS
@@ -1,3 +1,73 @@
|
||||
17 August 2003
|
||||
Added support for insertion of user code in the generated code.
|
||||
|
||||
16 August 2003
|
||||
Applied a patch by Gottfried Ganssauge that adds exception specifiers to
|
||||
wrapper functions and pointer declarations. Thanks a lot Gottfried!!
|
||||
|
||||
Applied a patch by Prabhu Ramachandran that fixes ae problem with the
|
||||
pure virtual method generation. Thanks again Prabhu!
|
||||
|
||||
10 August 2003
|
||||
Support for incremental generation of the code has been added. This changes
|
||||
how --multiple works; documentation of this new feature will follow. Thanks
|
||||
to Prabhu Ramachandran, that saw the need for this feature and discussed a
|
||||
solution.
|
||||
|
||||
Automatically convert \ to / in Windows systems before passing the paths to
|
||||
gccxml.
|
||||
|
||||
Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual
|
||||
methods were being definied incorrectly. Thanks a lot Prabhu!
|
||||
|
||||
7 July 2003
|
||||
Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method,
|
||||
and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr.
|
||||
Thanks a lot Prabhu!
|
||||
|
||||
Fixed a bug where the macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID was being
|
||||
called multiple times for the same type.
|
||||
Thanks to Gottfried Ganßauge for reporting this!
|
||||
|
||||
Fixed bug where using AllFromHeader didn't use bases<> when exporting
|
||||
hierarchies.
|
||||
|
||||
Fixed the staticmethod bug.
|
||||
|
||||
5 July 2003
|
||||
Changed how --multiple works: now it generates one cpp file for each pyste
|
||||
file, makeing easier to integrate Pyste with build systems.
|
||||
|
||||
4 July 2003
|
||||
Applied patch that solved a bug in ClassExporter and added a distutils install
|
||||
script (install/setup.py), both contributed by Prabhu Ramachandran.
|
||||
Thanks Prabhu!
|
||||
|
||||
2 July 2003
|
||||
Jim Wilson found a bug where types like "char**" were being interpreted as
|
||||
"char*". Thanks Jim!
|
||||
|
||||
16 June 2003
|
||||
Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours
|
||||
have changed:
|
||||
|
||||
- If you export a derived class without exporting its base classes, the derived
|
||||
class will explicitly export the bases's methods and attributes. Before, if
|
||||
you were interested in the bases's methods, you had to export the base
|
||||
classes too.
|
||||
|
||||
- Added a new function, no_override. When a member function is specified as
|
||||
"no_override", no virtual wrappers are generated for it, improving
|
||||
performance and letting the code more clean.
|
||||
|
||||
- There was a bug in which the policy of virtual member functions was being
|
||||
ignored (patch by Roman Sulzhyk).
|
||||
|
||||
Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig.
|
||||
|
||||
4 June 2003
|
||||
Major improvements in memory usage.
|
||||
|
||||
3 June 2003
|
||||
Appliced a patch from Giulio Eulisse that allows unnamed enumerations to be
|
||||
exported with an AllFromHeader construct. Thanks a lot Giulio!
|
||||
|
||||
12
pyste/TODO
Normal file
12
pyste/TODO
Normal file
@@ -0,0 +1,12 @@
|
||||
- Make Pyste accept already-generated xml files
|
||||
|
||||
- throw() declaration in virtual wrapper's member functions
|
||||
|
||||
- Allow protected methods to be overriden in Python
|
||||
|
||||
- Expose programmability to the Pyste files (listing members of a class, for
|
||||
instance)
|
||||
|
||||
- Virtual operators
|
||||
|
||||
- args() support
|
||||
@@ -24,7 +24,8 @@
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Suppose that you want to add a function to a class, turning it into a method:</p>
|
||||
Suppose that you want to add a function to a class, turning it into a member
|
||||
function:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>World
|
||||
</span><span class=special>{
|
||||
@@ -38,7 +39,7 @@ Suppose that you want to add a function to a class, turning it into a method:</p
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Here, we want to make <tt>greet</tt> work as a method of the class <tt>World</tt>. We do
|
||||
Here, we want to make <tt>greet</tt> work as a member function of the class <tt>World</tt>. We do
|
||||
that using the <tt>add_method</tt> construct:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>W </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
@@ -46,7 +47,7 @@ that using the <tt>add_method</tt> construct:</p>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Notice also that then you can rename it, set its policy, just like a regular
|
||||
method:</p>
|
||||
member function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>W</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=literal>'Greet'</span><span class=special>)
|
||||
</span></pre></code>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Exporting All Declarations from a Header</title>
|
||||
<title>Exporting An Entire Header</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="wrappers.html">
|
||||
<link rel="next" href="smart_pointers.html">
|
||||
@@ -12,7 +12,7 @@
|
||||
<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>
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Exporting An Entire Header</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -26,9 +26,9 @@
|
||||
</table>
|
||||
<p>
|
||||
Even thought Pyste can identify various elements in the C++ code, like virtual
|
||||
methods, attributes, and so on, one thing that it can't do is to guess the
|
||||
semantics of functions that return pointers or references. In this case, the
|
||||
user must manually specify the policy. Policies are explained in the
|
||||
member functions, attributes, and so on, one thing that it can't do is to
|
||||
guess the semantics of functions that return pointers or references. In this
|
||||
case, the user must manually specify the policy. Policies are explained in the
|
||||
<a href="../../doc/tutorial/doc/call_policies.html">
|
||||
tutorial</a>.</p>
|
||||
<p>
|
||||
@@ -44,8 +44,8 @@ becomes in Pyste: </p>
|
||||
<span class=identifier>return_internal_reference</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>))
|
||||
</span></pre></code>
|
||||
<p>
|
||||
The user can specify policies for functions and methods with the <tt>set_policy</tt>
|
||||
function:</p>
|
||||
The user can specify policies for functions and virtual member functions with
|
||||
the <tt>set_policy</tt> function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>f</span><span class=special>, </span><span class=identifier>return_internal_reference</span><span class=special>())
|
||||
</span><span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>return_value_policy</span><span class=special>(</span><span class=identifier>manage_new_object</span><span class=special>))
|
||||
@@ -54,10 +54,11 @@ function:</p>
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img> <b>What if a function or method needs a policy and the user
|
||||
doesn't set one?</b><br><br> If a function/method needs a policy and one was not
|
||||
set, Pyste will issue a error. The user should then go in the interface file
|
||||
and set the policy for it, otherwise the generated cpp won't compile.
|
||||
<img src="theme/note.gif"></img> <b>What if a function or member function needs a policy and
|
||||
the user doesn't set one?</b><br><br> If a function needs a policy and one
|
||||
was not set, Pyste will issue a error. The user should then go in the
|
||||
interface file and set the policy for it, otherwise the generated cpp won't
|
||||
compile.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -66,7 +67,7 @@ and set the policy for it, otherwise the generated cpp won't compile.
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img>
|
||||
Note that, for functions/methods that return <tt>const T&</tt>, the policy
|
||||
Note that, for functions that return <tt>const T&</tt>, the policy
|
||||
<tt>return_value_policy<copy_const_reference>()</tt> wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
|
||||
@@ -81,8 +81,8 @@ Usage:
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--multiple create various cpps (one for each pyste file), instead
|
||||
of only one (useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using do not declare "using namespace boost";
|
||||
@@ -165,8 +165,8 @@ invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
cpp file with Boost.Python code, with all the classes and functions exported.
|
||||
|
||||
Besides declaring the classes and functions, the user has a number of other
|
||||
options, like renaming classes and methods, excluding methods and attributes,
|
||||
and so on.
|
||||
options, like renaming e excluding classes and member functionis. Those are
|
||||
explained later on.
|
||||
|
||||
[h2 Basics]
|
||||
|
||||
@@ -200,7 +200,7 @@ That will expose the class, the free function and the enum found in [^hello.h].
|
||||
|
||||
[page:1 Renaming and Excluding]
|
||||
|
||||
You can easily rename functions, classes, methods, attributes, etc. Just use the
|
||||
You can easily rename functions, classes, member functions, attributes, etc. Just use the
|
||||
function [^rename], like this:
|
||||
|
||||
World = Class("World", "hello.h")
|
||||
@@ -208,7 +208,7 @@ function [^rename], like this:
|
||||
show = Function("choice", "hello.h")
|
||||
rename(show, "Show")
|
||||
|
||||
You can rename methods and attributes using this syntax:
|
||||
You can rename member functions and attributes using this syntax:
|
||||
|
||||
rename(World.greet, "Greet")
|
||||
rename(World.set, "Set")
|
||||
@@ -216,7 +216,7 @@ You can rename methods and attributes using this syntax:
|
||||
rename(choice.red, "Red")
|
||||
rename(choice.blue, "Blue")
|
||||
|
||||
You can exclude functions, classes, methods, attributes, etc, in the same way,
|
||||
You can exclude functions, classes, member functions, attributes, etc, in the same way,
|
||||
with the function [^exclude]:
|
||||
|
||||
exclude(World.greet)
|
||||
@@ -231,12 +231,25 @@ To access the operators of a class, access the member [^operator] like this
|
||||
|
||||
The string inside the brackets is the same as the name of the operator in C++.[br]
|
||||
|
||||
[h2 Virtual Member Functions]
|
||||
|
||||
Pyste automatically generates wrappers for virtual member functions, but you
|
||||
may want to disable this behaviour (for performance reasons, or to let the
|
||||
code more clean) if you do not plan to override the functions in Python. To do
|
||||
this, use the function [^final]:
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
final(C.foo) # C::foo is a virtual member function
|
||||
|
||||
No virtual wrapper code will be generated for the virtual member function
|
||||
C::foo that way.
|
||||
|
||||
[page:1 Policies]
|
||||
|
||||
Even thought Pyste can identify various elements in the C++ code, like virtual
|
||||
methods, attributes, and so on, one thing that it can't do is to guess the
|
||||
semantics of functions that return pointers or references. In this case, the
|
||||
user must manually specify the policy. Policies are explained in the
|
||||
member functions, attributes, and so on, one thing that it can't do is to
|
||||
guess the semantics of functions that return pointers or references. In this
|
||||
case, the user must manually specify the policy. Policies are explained in the
|
||||
[@../../doc/tutorial/doc/call_policies.html tutorial].
|
||||
|
||||
The policies in Pyste are named exactly as in Boost.Python, only the syntax is
|
||||
@@ -248,22 +261,23 @@ becomes in Pyste:
|
||||
|
||||
return_internal_reference(1, with_custodian_and_ward(1, 2))
|
||||
|
||||
The user can specify policies for functions and methods with the [^set_policy]
|
||||
function:
|
||||
The user can specify policies for functions and virtual member functions with
|
||||
the [^set_policy] function:
|
||||
|
||||
set_policy(f, return_internal_reference())
|
||||
set_policy(C.foo, return_value_policy(manage_new_object))
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] [*What if a function or method needs a policy and the user
|
||||
doesn't set one?][br][br] If a function/method needs a policy and one was not
|
||||
set, Pyste will issue a error. The user should then go in the interface file
|
||||
and set the policy for it, otherwise the generated cpp won't compile.
|
||||
[$theme/note.gif] [*What if a function or member function needs a policy and
|
||||
the user doesn't set one?][br][br] If a function needs a policy and one
|
||||
was not set, Pyste will issue a error. The user should then go in the
|
||||
interface file and set the policy for it, otherwise the generated cpp won't
|
||||
compile.
|
||||
]
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]
|
||||
Note that, for functions/methods that return [^const T&], the policy
|
||||
Note that, for functions that return [^const T&], the policy
|
||||
[^return_value_policy<copy_const_reference>()] wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
@@ -371,9 +385,9 @@ You can optionally declare the function in the interface file itself:
|
||||
names = Function("names", "test.h")
|
||||
set_wrapper(names, names_wrapper)
|
||||
|
||||
The same mechanism can be used with methods too. Just remember that the first
|
||||
parameter of wrappers for methods is a pointer to the class, like in
|
||||
Boost.Python:
|
||||
The same mechanism can be used with member functions too. Just remember that
|
||||
the first parameter of wrappers for member functions is a pointer to the
|
||||
class, as in:
|
||||
|
||||
struct C
|
||||
{
|
||||
@@ -394,10 +408,10 @@ And then in the interface file:
|
||||
[$theme/note.gif]Even though Boost.Python accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a [*pointer]. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual method.
|
||||
code to compile when you set a wrapper for a virtual member function.
|
||||
]
|
||||
|
||||
[page:1 Exporting All Declarations from a Header]
|
||||
[page:1 Exporting An Entire Header]
|
||||
|
||||
Pyste also supports a mechanism to export all declarations found in a header
|
||||
file. Suppose again our file, [^hello.h]:
|
||||
@@ -466,6 +480,16 @@ For [^std::auto_ptr]'s, use the function [^use_auto_ptr].
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.
|
||||
|
||||
[h2 Holders]
|
||||
|
||||
If only the converter for the smart pointers is not enough and you need to
|
||||
specify the smart pointer as the holder for a class, use the functions
|
||||
[^hold_with_shared_ptr] and [^hold_with_auto_ptr]:
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
hold_with_shared_ptr(C)
|
||||
Function('newC', 'C.h')
|
||||
Function('printC', 'C.h')
|
||||
|
||||
[page:1 Global Variables]
|
||||
|
||||
@@ -479,7 +503,8 @@ functions, and export those.
|
||||
|
||||
[page:1 Adding New Methods]
|
||||
|
||||
Suppose that you want to add a function to a class, turning it into a method:
|
||||
Suppose that you want to add a function to a class, turning it into a member
|
||||
function:
|
||||
|
||||
struct World
|
||||
{
|
||||
@@ -492,14 +517,14 @@ Suppose that you want to add a function to a class, turning it into a method:
|
||||
return w.msg;
|
||||
}
|
||||
|
||||
Here, we want to make [^greet] work as a method of the class [^World]. We do
|
||||
Here, we want to make [^greet] work as a member function of the class [^World]. We do
|
||||
that using the [^add_method] construct:
|
||||
|
||||
W = Class("World", "hello.h")
|
||||
add_method(W, "greet")
|
||||
|
||||
Notice also that then you can rename it, set its policy, just like a regular
|
||||
method:
|
||||
member function:
|
||||
|
||||
rename(W.greet, 'Greet')
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
You can easily rename functions, classes, methods, attributes, etc. Just use the
|
||||
You can easily rename functions, classes, member functions, attributes, etc. Just use the
|
||||
function <tt>rename</tt>, like this:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>World </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
@@ -34,7 +34,7 @@ function <tt>rename</tt>, like this:</p>
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>show</span><span class=special>, </span><span class=string>"Show"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
You can rename methods and attributes using this syntax:</p>
|
||||
You can rename member functions and attributes using this syntax:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>"Greet"</span><span class=special>)
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>"Set"</span><span class=special>)
|
||||
@@ -43,7 +43,7 @@ You can rename methods and attributes using this syntax:</p>
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>blue</span><span class=special>, </span><span class=string>"Blue"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
You can exclude functions, classes, methods, attributes, etc, in the same way,
|
||||
You can exclude functions, classes, member functions, attributes, etc, in the same way,
|
||||
with the function <tt>exclude</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>)
|
||||
@@ -59,6 +59,18 @@ To access the operators of a class, access the member <tt>operator</tt> like thi
|
||||
</span></pre></code>
|
||||
<p>
|
||||
The string inside the brackets is the same as the name of the operator in C++.<br></p>
|
||||
<a name="virtual_member_functions"></a><h2>Virtual Member Functions</h2><p>
|
||||
Pyste automatically generates wrappers for virtual member functions, but you
|
||||
may want to disable this behaviour (for performance reasons, or to let the
|
||||
code more clean) if you do not plan to override the functions in Python. To do
|
||||
this, use the function <tt>final</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>final</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>) </span>##<span class=identifier>C</span><span class=special>::</span><span class=identifier>foo </span><span class=identifier>is </span><span class=identifier>a </span><span class=keyword>virtual </span><span class=identifier>member </span><span class=identifier>function
|
||||
</span></pre></code>
|
||||
<p>
|
||||
No virtual wrapper code will be generated for the virtual member function
|
||||
C::foo that way.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
|
||||
@@ -55,8 +55,8 @@ Usage:
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--multiple create various cpps (one for each pyste file), instead
|
||||
of only one (useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using do not declare "using namespace boost";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Smart Pointers</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="exporting_all_declarations_from_a_header.html">
|
||||
<link rel="prev" href="exporting_an_entire_header.html">
|
||||
<link rel="next" href="global_variables.html">
|
||||
</head>
|
||||
<body>
|
||||
@@ -20,7 +20,7 @@
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -58,10 +58,20 @@ For <tt>std::auto_ptr</tt>'s, use the function <tt>use_auto_ptr</tt>.</p>
|
||||
<p>
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.</p>
|
||||
<a name="holders"></a><h2>Holders</h2><p>
|
||||
If only the converter for the smart pointers is not enough and you need to
|
||||
specify the smart pointer as the holder for a class, use the functions
|
||||
<tt>hold_with_shared_ptr</tt> and <tt>hold_with_auto_ptr</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>hold_with_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_an_entire_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="global_variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -32,8 +32,8 @@ cpp file with <a href="../../index.html">
|
||||
Boost.Python</a> code, with all the classes and functions exported.</p>
|
||||
<p>
|
||||
Besides declaring the classes and functions, the user has a number of other
|
||||
options, like renaming classes and methods, excluding methods and attributes,
|
||||
and so on. </p>
|
||||
options, like renaming e excluding classes and member functionis. Those are
|
||||
explained later on.</p>
|
||||
<a name="basics"></a><h2>Basics</h2><p>
|
||||
Suppose we have a class and some functions that we want to expose to Python
|
||||
declared in the header <tt>hello.h</tt>:</p>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<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">
|
||||
<link rel="next" href="exporting_an_entire_header.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -21,7 +21,7 @@
|
||||
<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>
|
||||
<td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
@@ -75,10 +75,9 @@ You can optionally declare the function in the interface file itself:</p>
|
||||
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=identifier>names_wrapper</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
The same mechanism can be used with methods too. Just remember that the first
|
||||
parameter of wrappers for methods is a pointer to the class, like in
|
||||
<a href="../../index.html">
|
||||
Boost.Python</a>:</p>
|
||||
The same mechanism can be used with member functions too. Just remember that
|
||||
the first parameter of wrappers for member functions is a pointer to the
|
||||
class, as in:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>C
|
||||
</span><span class=special>{
|
||||
@@ -104,7 +103,7 @@ And then in the interface file:</p>
|
||||
Boost.Python</a> accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a <b>pointer</b>. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual method.
|
||||
code to compile when you set a wrapper for a virtual member function.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -112,7 +111,7 @@ code to compile when you set a wrapper for a virtual method.
|
||||
<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>
|
||||
<td width="20"><a href="exporting_an_entire_header.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/exporting_all_declarations_from_a_header.html">Exporting All Declarations from a Header</a>
|
||||
<a href="doc/exporting_an_entire_header.html">Exporting An Entire Header</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
4
pyste/install/pyste.py
Normal file
4
pyste/install/pyste.py
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from Pyste import pyste
|
||||
pyste.main()
|
||||
18
pyste/install/setup.py
Normal file
18
pyste/install/setup.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# contributed by Prabhu Ramachandran
|
||||
|
||||
from distutils.core import setup
|
||||
import sys
|
||||
|
||||
setup (name = "Pyste",
|
||||
version = "0.9.10",
|
||||
description = "Pyste - Python Semi-Automatic Exporter",
|
||||
maintainer = "Bruno da Silva de Oliveira",
|
||||
maintainer_email = "nicodemus@globalite.com.br",
|
||||
licence = "Boost License",
|
||||
long_description = "Pyste is a Boost.Python code generator",
|
||||
url = "http://www.boost.org/libs/python/pyste/index.html",
|
||||
platforms = ['Any'],
|
||||
packages = ['Pyste'],
|
||||
scripts = ['pyste.py'],
|
||||
package_dir = {'Pyste': '../src/Pyste'},
|
||||
)
|
||||
@@ -1,117 +0,0 @@
|
||||
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
|
||||
self._cache = []
|
||||
self._CACHE_SIZE = 5
|
||||
|
||||
|
||||
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 UpdateCache(self, include, tail, decl_name, declarations, header):
|
||||
self._cache.append((include, tail, decl_name, declarations, header))
|
||||
if len(self._cache) > self._CACHE_SIZE:
|
||||
self._cache.pop(0)
|
||||
|
||||
|
||||
def Cache(self, include, tail, decl_name):
|
||||
for cache_include, cache_tail, cache_decl, declarations, header in self._cache:
|
||||
if cache_include == include \
|
||||
and cache_tail == tail \
|
||||
and cache_decl == decl_name:
|
||||
return declarations, header
|
||||
return None
|
||||
|
||||
|
||||
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, tail=None, decl_name=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.
|
||||
'''
|
||||
# check if this header was already parsed
|
||||
cached = self.Cache(include, tail, decl_name)
|
||||
if cached:
|
||||
return cached
|
||||
filename = self.FindFileName(include)
|
||||
# copy file to temp folder, if needed
|
||||
if tail:
|
||||
tempfilename = tempfile.mktemp('.h')
|
||||
infilename = tempfilename
|
||||
shutil.copyfile(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 decl_name is not None:
|
||||
cmd += ' "-fxml-start=%s"' % decl_name
|
||||
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)
|
||||
# cache the results
|
||||
self.UpdateCache(include, tail, decl_name, declarations, infilename)
|
||||
# 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
|
||||
@@ -1,104 +0,0 @@
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
import os
|
||||
import utils
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MultipleCodeUnit
|
||||
#==============================================================================
|
||||
class MultipleCodeUnit(object):
|
||||
'''
|
||||
Represents a bunch of cpp files, where each cpp file represents a header
|
||||
to be exported by pyste. Another cpp, named <module>.cpp is created too.
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, outdir):
|
||||
self.modulename = modulename
|
||||
self.outdir = outdir
|
||||
self.codeunits = {} # maps from a header to a SingleCodeUnit
|
||||
self.functions = []
|
||||
self._current = None
|
||||
|
||||
|
||||
def _FunctionName(self, code_unit_name):
|
||||
return '_Export_%s' % utils.makeid(code_unit_name)
|
||||
|
||||
|
||||
def _FileName(self, code_unit_name):
|
||||
filename = os.path.basename(code_unit_name)
|
||||
filename = '_%s.cpp' % os.path.splitext(filename)[0]
|
||||
return os.path.join(self.outdir, filename)
|
||||
|
||||
|
||||
def SetCurrent(self, code_unit_name):
|
||||
'Changes the current code unit'
|
||||
try:
|
||||
if code_unit_name is not None:
|
||||
codeunit = self.codeunits[code_unit_name]
|
||||
else:
|
||||
codeunit = None
|
||||
except KeyError:
|
||||
filename = self._FileName(code_unit_name)
|
||||
function_name = self._FunctionName(code_unit_name)
|
||||
codeunit = SingleCodeUnit(None, filename)
|
||||
codeunit.module_definition = 'void %s()' % function_name
|
||||
self.codeunits[code_unit_name] = codeunit
|
||||
if code_unit_name != '__all__':
|
||||
self.functions.append(function_name)
|
||||
self._current = codeunit
|
||||
|
||||
|
||||
def Current(self):
|
||||
return self._current
|
||||
|
||||
current = property(Current, SetCurrent)
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
if self._current is not None:
|
||||
self.current.Write(section, code)
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
if self._current is not None:
|
||||
return self.current.Section(section)
|
||||
|
||||
|
||||
def _CreateOutputDir(self):
|
||||
try:
|
||||
os.mkdir(self.outdir)
|
||||
except OSError: pass # already created
|
||||
|
||||
|
||||
def Save(self):
|
||||
# create the directory where all the files will go
|
||||
self._CreateOutputDir();
|
||||
# write all the codeunits, merging first the contents of
|
||||
# the special code unit named __all__
|
||||
__all__ = self.codeunits.get('__all__')
|
||||
for name, codeunit in self.codeunits.items():
|
||||
if name != '__all__':
|
||||
if __all__:
|
||||
codeunit.Merge(__all__)
|
||||
codeunit.Save()
|
||||
# generate the main cpp
|
||||
filename = os.path.join(self.outdir, self.modulename + '.cpp')
|
||||
fout = SmartFile(filename, 'w')
|
||||
fout.write(utils.left_equals('Include'))
|
||||
fout.write('#include <boost/python.hpp>\n\n')
|
||||
fout.write(utils.left_equals('Exports'))
|
||||
for function in self.functions:
|
||||
fout.write('void %s();\n' % function)
|
||||
fout.write('\n')
|
||||
fout.write(utils.left_equals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
|
||||
fout.write('{\n')
|
||||
indent = ' ' * 4
|
||||
for function in self.functions:
|
||||
fout.write(indent)
|
||||
fout.write('%s();\n' % function)
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from policies import *
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
from EnumExporter import EnumExporter
|
||||
from utils import makeid, enumerate
|
||||
from copy import deepcopy
|
||||
import copy
|
||||
import exporterutils
|
||||
import re
|
||||
|
||||
@@ -15,8 +15,7 @@ import re
|
||||
#==============================================================================
|
||||
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
|
||||
@@ -43,44 +42,37 @@ class ClassExporter(Exporter):
|
||||
self.wrapper_generator = None
|
||||
# a list of code units, generated by nested declarations
|
||||
self.nested_codeunits = []
|
||||
self._exported_opaque_pointers = {}
|
||||
|
||||
|
||||
def ScopeName(self):
|
||||
return makeid(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return makeid(self.class_.name)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.class_.FullName()
|
||||
return self.info.name
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
if self.declarations:
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.class_ = copy.deepcopy(self.class_)
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.public_members = \
|
||||
[x for x in self.class_.members if x.visibility == Scope.public]
|
||||
self.class_ = None
|
||||
|
||||
|
||||
def ClassBases(self):
|
||||
bases = []
|
||||
def GetBases(class_):
|
||||
this_bases = [self.GetDeclaration(x.name) for x in class_.bases]
|
||||
bases.extend(this_bases)
|
||||
for base in this_bases:
|
||||
GetBases(base)
|
||||
|
||||
GetBases(self.class_)
|
||||
return bases
|
||||
all_bases = []
|
||||
for level in self.class_.hierarchy:
|
||||
for base in level:
|
||||
all_bases.append(base)
|
||||
return [self.GetDeclaration(x.name) for x in all_bases]
|
||||
|
||||
|
||||
def Order(self):
|
||||
@@ -88,40 +80,67 @@ class ClassExporter(Exporter):
|
||||
bases' bases. Do this because base classes must be instantialized
|
||||
before the derived classes in the module definition.
|
||||
'''
|
||||
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
|
||||
num_bases = len(self.ClassBases())
|
||||
return num_bases, self.class_.FullName()
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
self.InheritMethods(exported_names)
|
||||
self.MakeNonVirtual()
|
||||
if not self.info.exclude:
|
||||
self.CheckIsForwardDeclared()
|
||||
self.CheckForwardDeclarations()
|
||||
self.ExportBasics()
|
||||
self.ExportBases(exported_names)
|
||||
self.ExportConstructors()
|
||||
self.ExportVariables()
|
||||
self.ExportMethods()
|
||||
self.ExportVirtualMethods()
|
||||
self.ExportMethods()
|
||||
self.ExportOperators()
|
||||
self.ExportNestedClasses(exported_names)
|
||||
self.ExportNestedEnums()
|
||||
self.ExportNestedEnums(exported_names)
|
||||
self.ExportSmartPointer()
|
||||
self.ExportOpaquePointerPolicies()
|
||||
self.Write(codeunit)
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def CheckIsForwardDeclared(self):
|
||||
if self.class_.incomplete:
|
||||
print "--> Error: Class %s is forward declared! " \
|
||||
"Please use the header with its complete definition." % self.class_.FullName()
|
||||
print
|
||||
|
||||
|
||||
def CheckForwardDeclarations(self):
|
||||
for m in self.public_members:
|
||||
if isinstance(m, Function):
|
||||
exporterutils.WarnForwardDeclarations(m)
|
||||
def InheritMethods(self, exported_names):
|
||||
'''Go up in the class hierarchy looking for classes that were not
|
||||
exported yet, and then add their public members to this classes
|
||||
members, as if they were members of this class. This allows the user to
|
||||
just export one type and automatically get all the members from the
|
||||
base classes.
|
||||
'''
|
||||
valid_members = (Method, ClassVariable, NestedClass, ClassEnumeration)
|
||||
# these don't work INVESTIGATE!: (ClassOperator, ConverterOperator)
|
||||
fullnames = [x.FullName() for x in self.class_]
|
||||
pointers = [x.PointerDeclaration(True) for x in self.class_ if isinstance(x, Method)]
|
||||
fullnames = dict([(x, None) for x in fullnames])
|
||||
pointers = dict([(x, None) for x in pointers])
|
||||
for level in self.class_.hierarchy:
|
||||
level_exported = False
|
||||
for base in level:
|
||||
base = self.GetDeclaration(base.name)
|
||||
if base.FullName() not in exported_names:
|
||||
for member in base:
|
||||
if type(member) in valid_members:
|
||||
member_copy = copy.deepcopy(member)
|
||||
member_copy.class_ = self.class_.FullName()
|
||||
if isinstance(member_copy, Method):
|
||||
pointer = member_copy.PointerDeclaration(True)
|
||||
if pointer not in pointers:
|
||||
self.class_.AddMember(member)
|
||||
pointers[pointer] = None
|
||||
elif member_copy.FullName() not in fullnames:
|
||||
self.class_.AddMember(member)
|
||||
else:
|
||||
level_exported = True
|
||||
if level_exported:
|
||||
break
|
||||
def IsValid(member):
|
||||
return isinstance(member, valid_members) and member.visibility == Scope.public
|
||||
self.public_members = [x for x in self.class_ if IsValid(x)]
|
||||
|
||||
|
||||
|
||||
def Write(self, codeunit):
|
||||
indent = self.INDENT
|
||||
boost_ns = namespaces.python
|
||||
@@ -184,23 +203,24 @@ class ClassExporter(Exporter):
|
||||
|
||||
|
||||
def ExportBasics(self):
|
||||
'Export the name of the class and its class_ statement'
|
||||
self.Add('template', self.class_.FullName())
|
||||
'''Export the name of the class and its class_ statement.'''
|
||||
class_name = self.class_.FullName()
|
||||
self.Add('template', class_name)
|
||||
name = self.info.rename or self.class_.name
|
||||
self.Add('constructor', '"%s"' % name)
|
||||
|
||||
|
||||
def ExportBases(self, exported_names):
|
||||
'Expose the bases of the class into the template section'
|
||||
bases = self.class_.bases
|
||||
bases_list = []
|
||||
for base in bases:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
bases_list.append(base.name)
|
||||
if bases_list:
|
||||
code = namespaces.python + 'bases< %s > ' % \
|
||||
(', '.join(bases_list))
|
||||
self.Add('template', code)
|
||||
hierarchy = self.class_.hierarchy
|
||||
exported = []
|
||||
for level in hierarchy:
|
||||
for base in level:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
exported.append(base.name)
|
||||
if exported:
|
||||
code = namespaces.python + 'bases< %s > ' % (', '.join(exported))
|
||||
self.Add('template', code)
|
||||
|
||||
|
||||
def ExportConstructors(self):
|
||||
@@ -311,19 +331,11 @@ class ClassExporter(Exporter):
|
||||
def Pointer(m):
|
||||
'returns the correct pointer declaration for the method m'
|
||||
# check if this method has a wrapper set for him
|
||||
wrapper = self.info[method.name].wrapper
|
||||
wrapper = self.info[m.name].wrapper
|
||||
if wrapper:
|
||||
return '&' + wrapper.FullName()
|
||||
# return normal pointers to the methods of the class
|
||||
if isinstance(m, Method):
|
||||
is_unique = self.class_.IsUnique(m.name)
|
||||
else:
|
||||
# function
|
||||
is_unique = len(self.GetDeclarations(m.FullName())) == 1
|
||||
if is_unique:
|
||||
return '&' + method.FullName()
|
||||
else:
|
||||
return method.PointerDeclaration()
|
||||
return m.PointerDeclaration()
|
||||
|
||||
def IsExportable(m):
|
||||
'Returns true if the given method is exportable by this routine'
|
||||
@@ -333,6 +345,8 @@ class ClassExporter(Exporter):
|
||||
methods = [x for x in self.public_members if IsExportable(x)]
|
||||
methods.extend(self.GetAddedMethods())
|
||||
|
||||
staticmethods = {}
|
||||
|
||||
for method in methods:
|
||||
method_info = self.info[method.name]
|
||||
|
||||
@@ -367,29 +381,48 @@ class ClassExporter(Exporter):
|
||||
self.Add('inside', code)
|
||||
# static method
|
||||
if isinstance(method, Method) and method.static:
|
||||
code = '.staticmethod("%s")' % name
|
||||
self.Add('inside', code)
|
||||
staticmethods[name] = 1
|
||||
# add wrapper code if this method has one
|
||||
wrapper = method_info.wrapper
|
||||
if wrapper and wrapper.code:
|
||||
self.Add('declaration', wrapper.code)
|
||||
|
||||
# export staticmethod statements
|
||||
for name in staticmethods:
|
||||
code = '.staticmethod("%s")' % name
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
|
||||
def MakeNonVirtual(self):
|
||||
'''Make all methods that the user indicated to no_override no more virtual, delegating their
|
||||
export to the ExportMethods routine'''
|
||||
for member in self.class_:
|
||||
if type(member) == Method and member.virtual:
|
||||
member.virtual = not self.info[member.name].no_override
|
||||
|
||||
|
||||
def ExportVirtualMethods(self):
|
||||
# check if this class has any virtual methods
|
||||
has_virtual_methods = False
|
||||
for member in self.class_.members:
|
||||
for member in self.class_:
|
||||
if type(member) == Method and member.virtual:
|
||||
has_virtual_methods = True
|
||||
break
|
||||
|
||||
holder = self.info.holder
|
||||
if has_virtual_methods:
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
|
||||
self.Add('template', generator.FullName())
|
||||
if holder:
|
||||
self.Add('template', holder(generator.FullName()))
|
||||
else:
|
||||
self.Add('template', generator.FullName())
|
||||
for definition in generator.GenerateDefinitions():
|
||||
self.Add('inside', definition)
|
||||
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
|
||||
|
||||
else:
|
||||
if holder:
|
||||
self.Add('template', holder(self.class_.FullName()))
|
||||
|
||||
# operators natively supported by boost
|
||||
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -='\
|
||||
@@ -398,7 +431,7 @@ class ClassExporter(Exporter):
|
||||
BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS))))
|
||||
|
||||
# a dict of operators that are not directly supported by boost, but can be exposed
|
||||
# simply as a function with a special signature
|
||||
# simply as a function with a special name
|
||||
BOOST_RENAME_OPERATORS = {
|
||||
'()' : '__call__',
|
||||
}
|
||||
@@ -471,8 +504,6 @@ class ClassExporter(Exporter):
|
||||
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
|
||||
@@ -545,10 +576,7 @@ class ClassExporter(Exporter):
|
||||
if info.rename or not special_code:
|
||||
# export as method
|
||||
name = info.rename or ConverterMethodName(converter)
|
||||
if self.class_.IsUnique(converter.name):
|
||||
pointer = '&' + converter.FullName()
|
||||
else:
|
||||
pointer = converter.PointerDeclaration()
|
||||
pointer = converter.PointerDeclaration()
|
||||
policy_code = ''
|
||||
if info.policy:
|
||||
policy_code = ', %s()' % info.policy.Code()
|
||||
@@ -566,22 +594,22 @@ class ClassExporter(Exporter):
|
||||
nested_info.include = self.info.include
|
||||
nested_info.name = nested_class.FullName()
|
||||
exporter = ClassExporter(nested_info)
|
||||
exporter.SetDeclarations(self.declarations + [nested_class])
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
def ExportNestedEnums(self):
|
||||
def ExportNestedEnums(self, exported_names):
|
||||
nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
|
||||
for enum in nested_enums:
|
||||
enum_info = self.info[enum.name]
|
||||
enum_info.include = self.info.include
|
||||
enum_info.name = enum.FullName()
|
||||
exporter = EnumExporter(enum_info)
|
||||
exporter.SetDeclarations(self.declarations + [enum])
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
exporter.Export(codeunit, None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
@@ -590,15 +618,7 @@ class ClassExporter(Exporter):
|
||||
if smart_ptr:
|
||||
class_name = self.class_.FullName()
|
||||
smart_ptr = smart_ptr % class_name
|
||||
#self.Add('template', smart_ptr)
|
||||
|
||||
self.Add('scope', '// Temporary code for smart pointers')
|
||||
self.Add('scope', namespaces.python + 'objects::class_value_wrapper< ')
|
||||
self.Add('scope', ' %s, objects::make_ptr_instance< ' % smart_ptr)
|
||||
self.Add('scope', ' %s, objects::pointer_holder< ' % class_name)
|
||||
self.Add('scope', ' %s, %s >' % (smart_ptr, class_name))
|
||||
self.Add('scope', ' >')
|
||||
self.Add('scope', '>();')
|
||||
self.Add('scope', '%sregister_ptr_to_python< %s >();' % (namespaces.python, smart_ptr))
|
||||
|
||||
|
||||
def ExportOpaquePointerPolicies(self):
|
||||
@@ -607,10 +627,9 @@ class ClassExporter(Exporter):
|
||||
for method in methods:
|
||||
return_opaque_policy = return_value_policy(return_opaque_pointer)
|
||||
if self.info[method.name].policy == return_opaque_policy:
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % method.result.name
|
||||
if macro not in self._exported_opaque_pointers:
|
||||
macro = exporterutils.EspecializeTypeID(method.result.name)
|
||||
if macro:
|
||||
self.Add('declaration-outside', macro)
|
||||
self._exported_opaque_pointers[macro] = 1
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -635,7 +654,7 @@ class _VirtualWrapperGenerator(object):
|
||||
'Generates code to export the virtual methods of the given class'
|
||||
|
||||
def __init__(self, class_, bases, info):
|
||||
self.class_ = class_
|
||||
self.class_ = copy.deepcopy(class_)
|
||||
self.bases = bases[:]
|
||||
self.info = info
|
||||
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
|
||||
@@ -676,7 +695,7 @@ class _VirtualWrapperGenerator(object):
|
||||
constantness = ' const'
|
||||
|
||||
# call_method callback
|
||||
decl = indent + '%s %s(%s)%s {\n' % (result, method.name, params, constantness)
|
||||
decl = indent + '%s %s(%s)%s%s {\n' % (result, method.name, params, constantness, method.Exceptions())
|
||||
param_names_str = ', '.join(param_names)
|
||||
if param_names_str:
|
||||
param_names_str = ', ' + param_names_str
|
||||
@@ -687,17 +706,26 @@ class _VirtualWrapperGenerator(object):
|
||||
# default implementations (with overloading)
|
||||
def DefaultImpl(method, param_names):
|
||||
'Return the body of a default implementation wrapper'
|
||||
indent2 = indent * 2
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if not wrapper:
|
||||
# return the default implementation of the class
|
||||
return '%s%s::%s(%s);\n' % \
|
||||
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
|
||||
if method.abstract:
|
||||
s = indent2 + 'PyErr_SetString(PyExc_RuntimeError, "pure virtual function called");\n' +\
|
||||
indent2 + 'throw_error_already_set();\n'
|
||||
params = ', '.join(param_names)
|
||||
s += indent2 + '%s%s(%s);\n' % \
|
||||
(return_str, method.name, params)
|
||||
return s
|
||||
else:
|
||||
return indent2 + '%s%s(%s);\n' % \
|
||||
(return_str, method.FullName(), ', '.join(param_names))
|
||||
else:
|
||||
# return a call for the wrapper
|
||||
params = ', '.join(['this'] + param_names)
|
||||
return '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
return indent2 + '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
|
||||
if not method.abstract and method.visibility != Scope.private:
|
||||
if method.visibility != Scope.private:
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
impl_names = self.DefaultImplementationNames(method)
|
||||
@@ -705,7 +733,7 @@ class _VirtualWrapperGenerator(object):
|
||||
params, param_names, param_types = _ParamsInfo(method, argNum)
|
||||
decl += '\n'
|
||||
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
|
||||
decl += indent*2 + DefaultImpl(method, param_names)
|
||||
decl += DefaultImpl(method, param_names)
|
||||
decl += indent + '}\n'
|
||||
return decl
|
||||
|
||||
@@ -720,7 +748,7 @@ class _VirtualWrapperGenerator(object):
|
||||
class_name = self.class_.FullName()
|
||||
wrapper_name = pyste + self.wrapper_name
|
||||
result = method.result.FullName()
|
||||
is_method_unique = self.IsMethodUnique(method.name)
|
||||
is_method_unique = method.is_unique
|
||||
constantness = ''
|
||||
if method.const:
|
||||
constantness = ' const'
|
||||
@@ -740,17 +768,19 @@ class _VirtualWrapperGenerator(object):
|
||||
default_pointers.append(default_pointer)
|
||||
|
||||
# get the pointer of the method
|
||||
if is_method_unique:
|
||||
pointer = '&' + method.FullName()
|
||||
else:
|
||||
pointer = method.PointerDeclaration()
|
||||
pointer = method.PointerDeclaration()
|
||||
|
||||
# Add policy to overloaded methods also
|
||||
policy = self.info[method.name].policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
|
||||
# generate the defs
|
||||
definitions = []
|
||||
# basic def
|
||||
definitions.append('.def("%s", %s, %s)' % (rename, pointer, default_pointers[-1]))
|
||||
definitions.append('.def("%s", %s, %s%s)' % (rename, pointer, default_pointers[-1], policy))
|
||||
for default_pointer in default_pointers[:-1]:
|
||||
definitions.append('.def("%s", %s)' % (rename, default_pointer))
|
||||
definitions.append('.def("%s", %s%s)' % (rename, default_pointer, policy))
|
||||
return definitions
|
||||
|
||||
|
||||
@@ -765,22 +795,17 @@ class _VirtualWrapperGenerator(object):
|
||||
This method creates the instance variable self.virtual_methods.
|
||||
'''
|
||||
def IsVirtual(m):
|
||||
return type(m) is Method and m.virtual and m.visibility != Scope.private
|
||||
|
||||
all_methods = [x for x in self.class_.members if IsVirtual(x)]
|
||||
for base in self.bases:
|
||||
base_methods = [x.Copy() for x in base if IsVirtual(x)]
|
||||
for base_method in base_methods:
|
||||
base_method.class_ = self.class_.FullName()
|
||||
all_methods.append(base_method)
|
||||
|
||||
return type(m) is Method and \
|
||||
m.virtual and \
|
||||
m.visibility != Scope.private
|
||||
|
||||
# extract the virtual methods, avoiding duplications. The duplication
|
||||
# must take in account the full signature without the class name, so
|
||||
# that inherited members are correctly excluded if the subclass overrides
|
||||
# them.
|
||||
def MethodSig(method):
|
||||
if method.const:
|
||||
const = 'const'
|
||||
const = ' const'
|
||||
else:
|
||||
const = ''
|
||||
if method.result:
|
||||
@@ -788,10 +813,23 @@ class _VirtualWrapperGenerator(object):
|
||||
else:
|
||||
result = ''
|
||||
params = ', '.join([x.FullName() for x in method.parameters])
|
||||
return '%s %s(%s) %s' % (result, method.name, params, const)
|
||||
|
||||
self.virtual_methods = []
|
||||
return '%s %s(%s)%s%s' % (
|
||||
result, method.name, params, const, method.Exceptions())
|
||||
|
||||
already_added = {}
|
||||
self.virtual_methods = []
|
||||
for member in self.class_:
|
||||
if IsVirtual(member):
|
||||
already_added[MethodSig(member)] = None
|
||||
self.virtual_methods.append(member)
|
||||
|
||||
for base in self.bases:
|
||||
base_methods = [copy.deepcopy(x) for x in base if IsVirtual(x)]
|
||||
for base_method in base_methods:
|
||||
self.class_.AddMember(base_method)
|
||||
|
||||
all_methods = [x for x in self.class_ if IsVirtual(x)]
|
||||
|
||||
for member in all_methods:
|
||||
sig = MethodSig(member)
|
||||
if IsVirtual(member) and not sig in already_added:
|
||||
@@ -799,17 +837,8 @@ class _VirtualWrapperGenerator(object):
|
||||
already_added[sig] = 0
|
||||
|
||||
|
||||
def IsMethodUnique(self, method):
|
||||
if not self._method_count:
|
||||
for m in self.virtual_methods:
|
||||
self._method_count[m.name] = self._method_count.get(m.name, 0) + 1
|
||||
return self._method_count[method] == 1
|
||||
|
||||
|
||||
def Constructors(self):
|
||||
def IsValid(m):
|
||||
return isinstance(m, Constructor) and m.visibility == Scope.public
|
||||
return [m for m in self.class_.members if IsValid(m)]
|
||||
return self.class_.Constructors(publics_only=True)
|
||||
|
||||
|
||||
def GenerateDefinitions(self):
|
||||
@@ -817,7 +846,7 @@ class _VirtualWrapperGenerator(object):
|
||||
for method in self.virtual_methods:
|
||||
exclude = self.info[method.name].exclude
|
||||
# generate definitions only for public methods and non-abstract methods
|
||||
if method.visibility == Scope.public and not method.abstract and not exclude:
|
||||
if method.visibility == Scope.public and not exclude:
|
||||
defs.extend(self.MethodDefinition(method))
|
||||
return defs
|
||||
|
||||
21
pyste/src/Pyste/CodeExporter.py
Normal file
21
pyste/src/Pyste/CodeExporter.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from Exporter import Exporter
|
||||
|
||||
#==============================================================================
|
||||
# CodeExporter
|
||||
#==============================================================================
|
||||
class CodeExporter(Exporter):
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.code
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
codeunit.Write(self.info.section, self.info.code)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
pass
|
||||
221
pyste/src/Pyste/CppParser.py
Normal file
221
pyste/src/Pyste/CppParser.py
Normal file
@@ -0,0 +1,221 @@
|
||||
from GCCXMLParser import ParseDeclarations
|
||||
import tempfile
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
import settings
|
||||
import shutil
|
||||
import shelve
|
||||
from cPickle import dump, load
|
||||
|
||||
#==============================================================================
|
||||
# exceptions
|
||||
#==============================================================================
|
||||
class CppParserError(Exception): pass
|
||||
|
||||
#==============================================================================
|
||||
# CppParser
|
||||
#==============================================================================
|
||||
class CppParser:
|
||||
'Parses a header file and returns a list of declarations'
|
||||
|
||||
def __init__(self, includes=None, defines=None, cache_dir=None):
|
||||
'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
|
||||
#if cache_dir is None:
|
||||
# cache_dir = tempfile.mktemp()
|
||||
# self.delete_cache = True
|
||||
#else:
|
||||
# self.delete_cache = False
|
||||
self.delete_cache = False
|
||||
self.cache_dir = cache_dir
|
||||
self.cache_files = []
|
||||
self.mem_cache = {}
|
||||
# create the cache dir
|
||||
if cache_dir:
|
||||
try:
|
||||
os.makedirs(cache_dir)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self.Close()
|
||||
|
||||
|
||||
def _IncludeParams(self, filename):
|
||||
includes = self.includes[:]
|
||||
filedir = os.path.dirname(filename)
|
||||
if not filedir:
|
||||
filedir = '.'
|
||||
includes.insert(0, filedir)
|
||||
includes = ['-I "%s"' % x for x in includes]
|
||||
return ' '.join(includes)
|
||||
|
||||
|
||||
def _DefineParams(self):
|
||||
defines = ['-D "%s"' % x for x in self.defines]
|
||||
return ' '.join(defines)
|
||||
|
||||
|
||||
def FindHeader(self, header):
|
||||
if os.path.isfile(header):
|
||||
return header
|
||||
for path in self.includes:
|
||||
filename = os.path.join(path, header)
|
||||
if os.path.isfile(filename):
|
||||
return filename
|
||||
else:
|
||||
name = os.path.basename(header)
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
|
||||
|
||||
def AppendTail(self, filename, tail):
|
||||
'''Creates a temporary file, appends the text tail to it, and returns
|
||||
the filename of the file.
|
||||
'''
|
||||
temp = tempfile.mktemp('.h')
|
||||
shutil.copyfile(filename, temp)
|
||||
f = file(temp, 'a')
|
||||
f.write('\n\n'+tail)
|
||||
f.close()
|
||||
return temp
|
||||
|
||||
|
||||
def ParseWithGCCXML(self, header, tail):
|
||||
'''Parses the given header using gccxml and GCCXMLParser.
|
||||
'''
|
||||
header = self.FindHeader(header)
|
||||
if tail:
|
||||
filename = self.AppendTail(header, tail)
|
||||
else:
|
||||
filename = header
|
||||
xmlfile = tempfile.mktemp('.xml')
|
||||
try:
|
||||
# get the params
|
||||
includes = self._IncludeParams(filename)
|
||||
defines = self._DefineParams()
|
||||
# call gccxml
|
||||
cmd = 'gccxml %s %s %s -fxml=%s'
|
||||
status = os.system(cmd % (includes, defines, filename, xmlfile))
|
||||
if status != 0 or not os.path.isfile(xmlfile):
|
||||
raise CppParserError, 'Error executing gccxml'
|
||||
# parse the resulting xml
|
||||
declarations = ParseDeclarations(xmlfile)
|
||||
# make the declarations' location to point to the original file
|
||||
if tail:
|
||||
for decl in declarations:
|
||||
decl_filename = os.path.normpath(os.path.normcase(decl.location[0]))
|
||||
filename = os.path.normpath(os.path.normcase(filename))
|
||||
if decl_filename == filename:
|
||||
decl.location = header, decl.location[1]
|
||||
# return the declarations
|
||||
return declarations
|
||||
finally:
|
||||
if settings.DEBUG and os.path.isfile(xmlfile):
|
||||
filename = os.path.basename(header)
|
||||
filename = os.path.splitext(filename)[0] + '.xml'
|
||||
shutil.copy(xmlfile, filename)
|
||||
# delete the temporary files
|
||||
try:
|
||||
os.remove(xmlfile)
|
||||
if tail:
|
||||
os.remove(filename)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def Parse(self, header, interface, tail=None):
|
||||
'''Parses the given filename related to the given interface and returns
|
||||
the (declarations, headerfile). The header returned is normally the
|
||||
same as the given to this method (except that it is the full path),
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to
|
||||
gccxml. This temp filename is then returned.
|
||||
'''
|
||||
if tail is None:
|
||||
tail = ''
|
||||
tail.strip()
|
||||
declarations = self.GetCache(header, interface, tail)
|
||||
if declarations is None:
|
||||
declarations = self.ParseWithGCCXML(header, tail)
|
||||
self.CreateCache(header, interface, tail, declarations)
|
||||
return declarations, header
|
||||
|
||||
|
||||
def CacheFileName(self, interface):
|
||||
interface_name = os.path.basename(interface)
|
||||
cache_file = os.path.splitext(interface_name)[0] + '.pystec'
|
||||
cache_file = os.path.join(self.cache_dir, cache_file)
|
||||
return cache_file
|
||||
|
||||
|
||||
def GetCache(self, header, interface, tail):
|
||||
key = (header, interface, tail)
|
||||
# try memory cache first
|
||||
if key in self.mem_cache:
|
||||
return self.mem_cache[key]
|
||||
|
||||
# get the cache from the disk
|
||||
if self.cache_dir is None:
|
||||
return None
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
cache = load(f)
|
||||
if cache.has_key(key):
|
||||
self.cache_files.append(cache_file)
|
||||
return cache[key]
|
||||
else:
|
||||
return None
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def CreateCache(self, header, interface, tail, declarations):
|
||||
key = (header, interface, tail)
|
||||
|
||||
# our memory cache only holds one item
|
||||
self.mem_cache.clear()
|
||||
self.mem_cache[key] = declarations
|
||||
|
||||
# save the cache in the disk
|
||||
if self.cache_dir is None:
|
||||
return
|
||||
header = self.FindHeader(header)
|
||||
cache_file = self.CacheFileName(interface)
|
||||
if os.path.isfile(cache_file):
|
||||
f = file(cache_file, 'rb')
|
||||
try:
|
||||
cache = load(f)
|
||||
finally:
|
||||
f.close()
|
||||
else:
|
||||
cache = {}
|
||||
cache[key] = declarations
|
||||
self.cache_files.append(cache_file)
|
||||
f = file(cache_file, 'wb')
|
||||
try:
|
||||
dump(cache, f, 1)
|
||||
finally:
|
||||
f.close()
|
||||
return cache_file
|
||||
|
||||
|
||||
def Close(self):
|
||||
if self.delete_cache and self.cache_files:
|
||||
for filename in self.cache_files:
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
self.cache_files = []
|
||||
shutil.rmtree(self.cache_dir)
|
||||
@@ -14,10 +14,13 @@ class EnumExporter(Exporter):
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
if self.declarations:
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
else:
|
||||
self.enum = None
|
||||
|
||||
|
||||
def Export(self, codeunit, expoted_names):
|
||||
def Export(self, codeunit, exported_names):
|
||||
if not self.info.exclude:
|
||||
indent = self.INDENT
|
||||
in_indent = self.INDENT*2
|
||||
@@ -34,11 +37,8 @@ class EnumExporter(Exporter):
|
||||
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
|
||||
code += indent + ';\n\n'
|
||||
codeunit.Write('module', code)
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
|
||||
def Order(self):
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
@@ -3,7 +3,7 @@ import os.path
|
||||
#==============================================================================
|
||||
# Exporter
|
||||
#==============================================================================
|
||||
class Exporter:
|
||||
class Exporter(object):
|
||||
'Base class for objects capable to generate boost.python code.'
|
||||
|
||||
INDENT = ' ' * 4
|
||||
@@ -11,10 +11,16 @@ class Exporter:
|
||||
def __init__(self, info, parser_tail=None):
|
||||
self.info = info
|
||||
self.parser_tail = parser_tail
|
||||
self.interface_file = None
|
||||
self.declarations = []
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
raise NotImplementedError(self.__class__.__name__)
|
||||
|
||||
|
||||
def Tail(self):
|
||||
return self.parser_tail
|
||||
|
||||
|
||||
def Parse(self, parser):
|
||||
@@ -26,6 +32,10 @@ class Exporter:
|
||||
self.SetDeclarations(declarations)
|
||||
|
||||
|
||||
def SetParsedHeader(self, parsed_header):
|
||||
self.parser_header = parsed_header
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
self.declarations = declarations
|
||||
|
||||
@@ -44,12 +54,11 @@ class Exporter:
|
||||
pass
|
||||
|
||||
|
||||
def Unit(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def GetDeclarations(self, fullname):
|
||||
decls = [x for x in self.declarations if x.FullName() == fullname]
|
||||
decls = []
|
||||
for decl in self.declarations:
|
||||
if decl.FullName() == fullname:
|
||||
decls.append(decl)
|
||||
if not decls:
|
||||
raise RuntimeError, 'no %s declaration found!' % fullname
|
||||
return decls
|
||||
@@ -57,7 +66,7 @@ class Exporter:
|
||||
|
||||
def GetDeclaration(self, fullname):
|
||||
decls = self.GetDeclarations(fullname)
|
||||
assert len(decls) == 1
|
||||
#assert len(decls) == 1
|
||||
return decls[0]
|
||||
|
||||
|
||||
@@ -65,8 +74,15 @@ class Exporter:
|
||||
'''Returns a string that uniquely identifies this instance. All
|
||||
exporters will be sorted by Order before being exported.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
def Header(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.Name() == other.Name()
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.Name() != other.Name()
|
||||
@@ -14,18 +14,17 @@ class FunctionExporter(Exporter):
|
||||
|
||||
def __init__(self, info, tail=None):
|
||||
Exporter.__init__(self, info, tail)
|
||||
self._exported_opaque_pointers = {}
|
||||
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
if not self.info.exclude:
|
||||
decls = self.GetDeclarations(self.info.name)
|
||||
for decl in decls:
|
||||
self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
|
||||
exporterutils.WarnForwardDeclarations(decl)
|
||||
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
|
||||
self.ExportOpaquePointer(decl, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
exported_names[self.Name()] = 1
|
||||
|
||||
|
||||
def ExportDeclaration(self, decl, unique, codeunit):
|
||||
@@ -34,10 +33,8 @@ class FunctionExporter(Exporter):
|
||||
wrapper = self.info.wrapper
|
||||
if wrapper:
|
||||
pointer = '&' + wrapper.FullName()
|
||||
elif not unique:
|
||||
pointer = decl.PointerDeclaration()
|
||||
else:
|
||||
pointer = '&' + decl.FullName()
|
||||
pointer = decl.PointerDeclaration()
|
||||
defs += pointer
|
||||
defs += self.PolicyCode()
|
||||
overload = self.OverloadName(decl)
|
||||
@@ -47,7 +44,7 @@ class FunctionExporter(Exporter):
|
||||
codeunit.Write('module', self.INDENT + defs + '\n')
|
||||
# add the code of the wrapper
|
||||
if wrapper and wrapper.code:
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
codeunit.Write('declaration', wrapper.code + '\n')
|
||||
|
||||
|
||||
def OverloadName(self, decl):
|
||||
@@ -64,7 +61,7 @@ class FunctionExporter(Exporter):
|
||||
overload = self.OverloadName(decl)
|
||||
if overload and overload not in codes:
|
||||
code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\
|
||||
(overload, decl.FullName(), decl.minArgs, decl.maxArgs)
|
||||
(overload, decl.FullName(), decl.minArgs, decl_.maxArgs)
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
codes[overload] = None
|
||||
|
||||
@@ -80,16 +77,11 @@ class FunctionExporter(Exporter):
|
||||
|
||||
def ExportOpaquePointer(self, function, codeunit):
|
||||
if self.info.policy == return_value_policy(return_opaque_pointer):
|
||||
type = function.result.name
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % type
|
||||
if macro not in self._exported_opaque_pointers:
|
||||
typename = function.result.name
|
||||
macro = exporterutils.EspecializeTypeID(typename)
|
||||
if macro:
|
||||
codeunit.Write('declaration-outside', macro)
|
||||
self._exported_opaque_pointers[macro] = 1
|
||||
|
||||
|
||||
def Order(self):
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
@@ -2,8 +2,12 @@ from declarations import *
|
||||
from elementtree.ElementTree import ElementTree
|
||||
from xml.parsers.expat import ExpatError
|
||||
from copy import deepcopy
|
||||
from utils import enumerate
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Exceptions
|
||||
#==============================================================================
|
||||
class InvalidXMLError(Exception): pass
|
||||
|
||||
class ParserError(Exception): pass
|
||||
@@ -11,6 +15,9 @@ class ParserError(Exception): pass
|
||||
class InvalidContextError(ParserError): pass
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# GCCXMLParser
|
||||
#==============================================================================
|
||||
class GCCXMLParser(object):
|
||||
'Parse a GCC_XML file and extract the top-level declarations.'
|
||||
|
||||
@@ -20,6 +27,7 @@ class GCCXMLParser(object):
|
||||
self.elements = self.GetElementsFromXML(filename)
|
||||
# high level declarations
|
||||
self.declarations = []
|
||||
self._names = {}
|
||||
# parse the elements
|
||||
for id in self.elements:
|
||||
element, decl = self.elements[id]
|
||||
@@ -36,6 +44,12 @@ class GCCXMLParser(object):
|
||||
|
||||
|
||||
def AddDecl(self, decl):
|
||||
if decl.FullName() in self._names:
|
||||
decl.is_unique= False
|
||||
for d in self.declarations:
|
||||
if d.FullName() == decl.FullName():
|
||||
d.is_unique = False
|
||||
self._names[decl.FullName()] = 0
|
||||
self.declarations.append(decl)
|
||||
|
||||
|
||||
@@ -101,7 +115,7 @@ class GCCXMLParser(object):
|
||||
restricted, id = Check(id, 'r')
|
||||
decl = self.GetDecl(id)
|
||||
if isinstance(decl, Type):
|
||||
res = decl.Copy()
|
||||
res = deepcopy(decl)
|
||||
if const:
|
||||
res.const = const
|
||||
if volatile:
|
||||
@@ -112,7 +126,6 @@ class GCCXMLParser(object):
|
||||
res = Type(decl.FullName(), const)
|
||||
res.volatile = volatile
|
||||
res.restricted = restricted
|
||||
res.incomplete = decl.incomplete
|
||||
return res
|
||||
|
||||
|
||||
@@ -129,8 +142,7 @@ class GCCXMLParser(object):
|
||||
|
||||
def ParseUnknown(self, id, element):
|
||||
name = '__Unknown_Element_%s' % id
|
||||
namespace = '::'
|
||||
decl = Declaration(name, namespace)
|
||||
decl = Unknown(name)
|
||||
self.Update(id, decl)
|
||||
|
||||
|
||||
@@ -138,10 +150,10 @@ class GCCXMLParser(object):
|
||||
namespace = element.get('name')
|
||||
context = element.get('context')
|
||||
if context:
|
||||
outerns = self.GetDecl(context)
|
||||
if not outerns.endswith('::'):
|
||||
outerns += '::'
|
||||
namespace = outerns + namespace
|
||||
outer = self.GetDecl(context)
|
||||
if not outer.endswith('::'):
|
||||
outer += '::'
|
||||
namespace = outer + namespace
|
||||
if namespace.startswith('::'):
|
||||
namespace = namespace[2:]
|
||||
self.Update(id, namespace)
|
||||
@@ -154,7 +166,7 @@ class GCCXMLParser(object):
|
||||
|
||||
def ParseVariable(self, id, element):
|
||||
# in gcc_xml, a static Field is declared as a Variable, so we check
|
||||
# this and call the Field parser if apply.
|
||||
# this and call the Field parser.
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, Class):
|
||||
self.ParseField(id, element)
|
||||
@@ -175,12 +187,23 @@ class GCCXMLParser(object):
|
||||
args = []
|
||||
for child in element:
|
||||
if child.tag == 'Argument':
|
||||
type_ = self.GetType(child.get('type'))
|
||||
type_.default = child.get('default')
|
||||
args.append(type_)
|
||||
type = self.GetType(child.get('type'))
|
||||
type.default = child.get('default')
|
||||
args.append(type)
|
||||
return args
|
||||
|
||||
|
||||
def GetExceptions(self, exception_list):
|
||||
if exception_list is None:
|
||||
return None
|
||||
|
||||
exceptions = []
|
||||
for t in exception_list.split():
|
||||
exceptions.append(self.GetType(t))
|
||||
|
||||
return exceptions
|
||||
|
||||
|
||||
def ParseFunction(self, id, element, functionType=Function):
|
||||
'''functionType is used because a Operator is identical to a normal
|
||||
function, only the type of the function changes.'''
|
||||
@@ -189,7 +212,9 @@ class GCCXMLParser(object):
|
||||
namespace = self.GetDecl(element.get('context'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
function = functionType(name, namespace, returns, params)
|
||||
incomplete = bool(int(element.get('incomplete', 0)))
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
function = functionType(name, namespace, returns, params, throws)
|
||||
function.location = location
|
||||
self.AddDecl(function)
|
||||
self.Update(id, function)
|
||||
@@ -199,14 +224,18 @@ class GCCXMLParser(object):
|
||||
self.ParseFunction(id, element, Operator)
|
||||
|
||||
|
||||
def GetBases(self, bases):
|
||||
'Parses the string "bases" from the xml into a list of Base instances.'
|
||||
def GetHierarchy(self, bases):
|
||||
'''Parses the string "bases" from the xml into a list of tuples of Base
|
||||
instances. The first tuple is the most direct inheritance, and then it
|
||||
goes up in the hierarchy.
|
||||
'''
|
||||
|
||||
if bases is None:
|
||||
return []
|
||||
bases = bases.split()
|
||||
baseobjs = []
|
||||
for base in bases:
|
||||
base_names = bases.split()
|
||||
this_level = []
|
||||
next_levels = []
|
||||
for base in base_names:
|
||||
# get the visibility
|
||||
split = base.split(':')
|
||||
if len(split) == 2:
|
||||
@@ -214,20 +243,40 @@ class GCCXMLParser(object):
|
||||
base = split[1]
|
||||
else:
|
||||
visib = Scope.public
|
||||
decl = self.GetDecl(base)
|
||||
baseobj = Base(decl.FullName(), visib)
|
||||
baseobjs.append(baseobj)
|
||||
return baseobjs
|
||||
decl = self.GetDecl(base)
|
||||
if not isinstance(decl, Class):
|
||||
# on windows, there are some classes which "bases" points to an
|
||||
# "Unimplemented" tag, but we are not interested in this classes
|
||||
# anyway
|
||||
continue
|
||||
base = Base(decl.FullName(), visib)
|
||||
this_level.append(base)
|
||||
# normalize with the other levels
|
||||
for index, level in enumerate(decl.hierarchy):
|
||||
if index < len(next_levels):
|
||||
next_levels[index] = next_levels[index] + level
|
||||
else:
|
||||
next_levels.append(level)
|
||||
hierarchy = []
|
||||
if this_level:
|
||||
hierarchy.append(tuple(this_level))
|
||||
if next_levels:
|
||||
hierarchy.extend(next_levels)
|
||||
return hierarchy
|
||||
|
||||
|
||||
def GetMembers(self, members):
|
||||
def GetMembers(self, member_list):
|
||||
# members must be a string with the ids of the members
|
||||
if members is None:
|
||||
if member_list is None:
|
||||
return []
|
||||
memberobjs = []
|
||||
for member in members.split():
|
||||
memberobjs.append(self.GetDecl(member))
|
||||
return memberobjs
|
||||
members = []
|
||||
for member in member_list.split():
|
||||
decl = self.GetDecl(member)
|
||||
if type(decl) in Class.ValidMemberTypes():
|
||||
if type(decl) is str:
|
||||
print decl
|
||||
members.append(decl)
|
||||
return members
|
||||
|
||||
|
||||
def ParseClass(self, id, element):
|
||||
@@ -235,23 +284,29 @@ class GCCXMLParser(object):
|
||||
abstract = bool(int(element.get('abstract', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
incomplete = bool(element.get('incomplete', False))
|
||||
incomplete = bool(int(element.get('incomplete', 0)))
|
||||
if isinstance(context, str):
|
||||
class_ = Class(name, context, [], abstract, [])
|
||||
self.AddDecl(class_)
|
||||
class_ = Class(name, context, [], abstract)
|
||||
else:
|
||||
# a nested class
|
||||
visib = element.get('access', Scope.public)
|
||||
class_ = NestedClass(
|
||||
name, context.FullName(), visib, [], abstract, [])
|
||||
name, context.FullName(), visib, [], abstract)
|
||||
class_.incomplete = incomplete
|
||||
# we have to add the declaration of the class before trying
|
||||
# to parse its members and bases, to avoid recursion.
|
||||
self.AddDecl(class_)
|
||||
class_.location = location
|
||||
class_.incomplete = incomplete
|
||||
self.Update(id, class_)
|
||||
# now we can get the members and the bases
|
||||
class_.bases = self.GetBases(element.get('bases'))
|
||||
class_.members = self.GetMembers(element.get('members'))
|
||||
class_.hierarchy = self.GetHierarchy(element.get('bases'))
|
||||
if class_.hierarchy:
|
||||
class_.bases = class_.hierarchy[0]
|
||||
members = self.GetMembers(element.get('members'))
|
||||
for member in members:
|
||||
if type(member) is str:
|
||||
print member
|
||||
class_.AddMember(member)
|
||||
|
||||
|
||||
def ParseStruct(self, id, element):
|
||||
@@ -265,26 +320,24 @@ class GCCXMLParser(object):
|
||||
|
||||
|
||||
def ParseArrayType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
type = self.GetType(element.get('type'))
|
||||
min = element.get('min')
|
||||
max = element.get('max')
|
||||
array = ArrayType(type_.name, type_.const)
|
||||
array.min = min
|
||||
array.max = max
|
||||
array = ArrayType(type.name, type.const, min, max)
|
||||
self.Update(id, array)
|
||||
|
||||
|
||||
def ParseReferenceType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = ReferenceType(type_.name, type_.const, None, type_.incomplete, expand)
|
||||
type = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type, FunctionType)
|
||||
ref = ReferenceType(type.name, type.const, None, expand, type.suffix)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
def ParsePointerType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = PointerType(type_.name, type_.const, None, type_.incomplete, expand)
|
||||
type = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type, FunctionType)
|
||||
ref = PointerType(type.name, type.const, None, expand, type.suffix)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
@@ -325,9 +378,10 @@ class GCCXMLParser(object):
|
||||
abstract = bool(int(element.get('pure_virtual', '0')))
|
||||
const = bool(int(element.get('const', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
throws = self.GetExceptions(element.get('throw', None))
|
||||
params = self.GetArguments(element)
|
||||
method = methodType(
|
||||
name, classname, result, params, visib, virtual, abstract, static, const)
|
||||
name, classname, result, params, visib, virtual, abstract, static, const, throws)
|
||||
method.location = location
|
||||
self.Update(id, method)
|
||||
|
||||
@@ -377,42 +431,23 @@ class GCCXMLParser(object):
|
||||
name = element.get('name')
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
incomplete = bool(int(element.get('incomplete', 0)))
|
||||
if isinstance(context, str):
|
||||
enum = Enumeration(name, context)
|
||||
self.AddDecl(enum) # in this case, is a top level decl
|
||||
else:
|
||||
visib = element.get('access', Scope.public)
|
||||
enum = ClassEnumeration(name, context.FullName(), visib)
|
||||
|
||||
self.AddDecl(enum)
|
||||
enum.location = location
|
||||
for child in element:
|
||||
if child.tag == 'EnumValue':
|
||||
name = child.get('name')
|
||||
value = int(child.get('init'))
|
||||
enum.values[name] = value
|
||||
enum.incomplete = incomplete
|
||||
self.Update(id, enum)
|
||||
|
||||
|
||||
def ParseUnimplemented(self, id, element):
|
||||
'No idea of what this is'
|
||||
self.Update(id, Declaration('', ''))
|
||||
|
||||
|
||||
def ParseUnion(self, id, element):
|
||||
name = element.get('name')
|
||||
context = self.GetDecl(element.get('context'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
if isinstance(context, str):
|
||||
# a free union
|
||||
union = Union(name, context)
|
||||
self.AddDecl(union)
|
||||
else:
|
||||
visib = element.get('access', Scope.public)
|
||||
union = ClassUnion(name, context.FullName(), visib)
|
||||
union.location = location
|
||||
self.Update(id, union)
|
||||
|
||||
|
||||
|
||||
def ParseDeclarations(filename):
|
||||
'Returns a list of the top declarations found in the gcc_xml file.'
|
||||
@@ -7,6 +7,7 @@ from infos import *
|
||||
from declarations import *
|
||||
import os.path
|
||||
import exporters
|
||||
import MultipleCodeUnit
|
||||
|
||||
#==============================================================================
|
||||
# HeaderExporter
|
||||
@@ -22,24 +23,23 @@ class HeaderExporter(Exporter):
|
||||
pass
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
def IsInternalName(name):
|
||||
'''Returns true if the given name looks like a internal compiler
|
||||
structure'''
|
||||
return name.startswith('_')
|
||||
def IsInternalName(self, name):
|
||||
'''Returns true if the given name looks like a internal compiler
|
||||
structure'''
|
||||
return name.startswith('_')
|
||||
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
header = os.path.normpath(self.parser_header)
|
||||
for decl in declarations:
|
||||
for decl in self.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)
|
||||
if location == header and not self.IsInternalName(decl.name):
|
||||
# ok, check the type of the declaration and export it accordingly
|
||||
self.HandleDeclaration(decl, codeunit, exported_names)
|
||||
|
||||
|
||||
def HandleDeclaration(self, decl):
|
||||
def HandleDeclaration(self, decl, codeunit, exported_names):
|
||||
'''Dispatch the declaration to the appropriate method, that must create
|
||||
a suitable info object for a Exporter, create a Exporter, set its
|
||||
declarations and append it to the list of exporters.
|
||||
@@ -53,25 +53,24 @@ class HeaderExporter(Exporter):
|
||||
|
||||
exporter_class = dispatch_table.get(type(decl))
|
||||
if exporter_class is not None:
|
||||
self.HandleExporter(decl, exporter_class)
|
||||
self.HandleExporter(decl, exporter_class, codeunit, exported_names)
|
||||
|
||||
|
||||
def HandleExporter(self, decl, exporter_type):
|
||||
def HandleExporter(self, decl, exporter_type, codeunit, exported_names):
|
||||
# only export complete declarations
|
||||
if not getattr(decl, "incomplete", False):
|
||||
if not decl.incomplete:
|
||||
info = self.info[decl.name]
|
||||
info.name = decl.FullName()
|
||||
info.include = self.info.include
|
||||
exporter = exporter_type(info)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return None # doesn't write anything by himself
|
||||
exporter.SetParsedHeader(self.parser_header)
|
||||
if isinstance(codeunit, MultipleCodeUnit.MultipleCodeUnit):
|
||||
codeunit.SetCurrent(self.interface_file, exporter.Name())
|
||||
else:
|
||||
codeunit.SetCurrent(exporter.Name())
|
||||
exporter.GenerateCode(codeunit, exported_names)
|
||||
|
||||
|
||||
def Order(self):
|
||||
def Name(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ class IncludeExporter(Exporter):
|
||||
def Parse(self, parser):
|
||||
pass
|
||||
|
||||
def Order(self):
|
||||
return self.info.include
|
||||
def Name(self):
|
||||
return '__all__'
|
||||
|
||||
def Unit(self):
|
||||
return '__all__' # include it in all generated cpps (multiple mode)
|
||||
def Header(self):
|
||||
return None # means "don't try to parse me!"
|
||||
130
pyste/src/Pyste/MultipleCodeUnit.py
Normal file
130
pyste/src/Pyste/MultipleCodeUnit.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
import os
|
||||
import utils
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MultipleCodeUnit
|
||||
#==============================================================================
|
||||
class MultipleCodeUnit(object):
|
||||
'''
|
||||
Represents a bunch of cpp files, where each cpp file represents a header
|
||||
to be exported by pyste. Another cpp, named <module>.cpp is created too.
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, outdir):
|
||||
self.modulename = modulename
|
||||
self.outdir = outdir
|
||||
self.codeunits = {} # maps from a (filename, function) to a SingleCodeUnit
|
||||
self.functions = []
|
||||
self._current = None
|
||||
self.all = SingleCodeUnit(None, None)
|
||||
|
||||
|
||||
def _FunctionName(self, interface_file):
|
||||
name = os.path.splitext(interface_file)[0]
|
||||
return 'Export_%s' % utils.makeid(name)
|
||||
|
||||
|
||||
def _FileName(self, interface_file):
|
||||
filename = os.path.basename(interface_file)
|
||||
filename = '_%s.cpp' % os.path.splitext(filename)[0]
|
||||
return os.path.join(self.outdir, filename)
|
||||
|
||||
|
||||
def SetCurrent(self, interface_file, export_name):
|
||||
'Changes the current code unit'
|
||||
if export_name is None:
|
||||
self._current = None
|
||||
elif export_name is '__all__':
|
||||
self._current = self.all
|
||||
else:
|
||||
filename = self._FileName(interface_file)
|
||||
function = self._FunctionName(interface_file)
|
||||
try:
|
||||
codeunit = self.codeunits[filename]
|
||||
except KeyError:
|
||||
codeunit = SingleCodeUnit(None, filename)
|
||||
codeunit.module_definition = 'void %s()' % function
|
||||
self.codeunits[filename] = codeunit
|
||||
if function not in self.functions:
|
||||
self.functions.append(function)
|
||||
self._current = codeunit
|
||||
|
||||
|
||||
def Current(self):
|
||||
return self._current
|
||||
|
||||
current = property(Current, SetCurrent)
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
if self._current is not None:
|
||||
self.current.Write(section, code)
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
if self._current is not None:
|
||||
return self.current.Section(section)
|
||||
|
||||
|
||||
def _CreateOutputDir(self):
|
||||
try:
|
||||
os.mkdir(self.outdir)
|
||||
except OSError: pass # already created
|
||||
|
||||
|
||||
def Save(self):
|
||||
# create the directory where all the files will go
|
||||
self._CreateOutputDir();
|
||||
# order all code units by filename, and merge them all
|
||||
codeunits = {} # filename => list of codeunits
|
||||
|
||||
# While ordering all code units by file name, the first code
|
||||
# unit in the list of code units is used as the main unit
|
||||
# which dumps all the include, declaration and
|
||||
# declaration-outside sections at the top of the file.
|
||||
for filename, codeunit in self.codeunits.items():
|
||||
if filename not in codeunits:
|
||||
# this codeunit is the main codeunit.
|
||||
codeunits[filename] = [codeunit]
|
||||
codeunit.Merge(self.all)
|
||||
else:
|
||||
main_unit = codeunits[filename][0]
|
||||
for section in ('include', 'declaration', 'declaration-outside'):
|
||||
main_unit.code[section] = main_unit.code[section] + codeunit.code[section]
|
||||
codeunit.code[section] = ''
|
||||
codeunits[filename].append(codeunit)
|
||||
|
||||
# Now write all the codeunits appending them correctly.
|
||||
for file_units in codeunits.values():
|
||||
append = False
|
||||
for codeunit in file_units:
|
||||
codeunit.Save(append)
|
||||
if not append:
|
||||
append = True
|
||||
|
||||
|
||||
def GenerateMain(self, interfaces):
|
||||
# generate the main cpp
|
||||
filename = os.path.join(self.outdir, '_main.cpp')
|
||||
fout = SmartFile(filename, 'w')
|
||||
fout.write(utils.left_equals('Include'))
|
||||
fout.write('#include <boost/python/module.hpp>\n\n')
|
||||
fout.write(utils.left_equals('Exports'))
|
||||
functions = [self._FunctionName(x) for x in interfaces]
|
||||
for function in functions:
|
||||
fout.write('void %s();\n' % function)
|
||||
fout.write('\n')
|
||||
fout.write(utils.left_equals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
|
||||
fout.write('{\n')
|
||||
indent = ' ' * 4
|
||||
for function in functions:
|
||||
fout.write(indent)
|
||||
fout.write('%s();\n' % function)
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class SingleCodeUnit:
|
||||
# define the avaiable sections
|
||||
self.code = {}
|
||||
# include section
|
||||
self.code['include'] = ''
|
||||
self.code['include'] = '#include <boost/python.hpp>\n'
|
||||
# declaration section (inside namespace)
|
||||
self.code['declaration'] = ''
|
||||
# declaration (outside namespace)
|
||||
@@ -49,19 +49,31 @@ class SingleCodeUnit:
|
||||
def Section(self, section):
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def SetCurrent(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
def Current(self):
|
||||
pass
|
||||
|
||||
|
||||
def Save(self):
|
||||
def Save(self, append=False):
|
||||
'Writes this code unit to the filename'
|
||||
space = '\n\n'
|
||||
fout = SmartFile(self.filename, 'w')
|
||||
if not append:
|
||||
flag = 'w'
|
||||
else:
|
||||
flag = 'a'
|
||||
fout = SmartFile(self.filename, flag)
|
||||
# includes
|
||||
includes = remove_duplicated_lines(self.code['include'])
|
||||
fout.write('\n' + left_equals('Includes'))
|
||||
fout.write('#include <boost/python.hpp>\n')
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
if self.code['include']:
|
||||
includes = remove_duplicated_lines(self.code['include'])
|
||||
fout.write('\n' + left_equals('Includes'))
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
# using
|
||||
if settings.USING_BOOST_NS:
|
||||
if settings.USING_BOOST_NS and not append:
|
||||
fout.write(left_equals('Using'))
|
||||
fout.write('using namespace boost::python;\n\n')
|
||||
# declarations
|
||||
@@ -69,16 +81,18 @@ class SingleCodeUnit:
|
||||
declaration_outside = self.code['declaration-outside']
|
||||
if declaration_outside or declaration:
|
||||
fout.write(left_equals('Declarations'))
|
||||
fout.write(declaration_outside + '\n\n')
|
||||
if declaration_outside:
|
||||
fout.write(declaration_outside + '\n\n')
|
||||
if declaration:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write('namespace %s {\n\n\n' % pyste_namespace)
|
||||
fout.write('namespace %s {\n\n' % pyste_namespace)
|
||||
fout.write(declaration)
|
||||
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write('\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(left_equals('Module'))
|
||||
fout.write(self.module_definition + '\n')
|
||||
fout.write('{\n')
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n')
|
||||
fout.write('}\n\n')
|
||||
fout.close()
|
||||
@@ -28,8 +28,8 @@ class VarExporter(Exporter):
|
||||
|
||||
|
||||
def Order(self):
|
||||
return 0, self.info.name
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
0
pyste/src/Pyste/__init__.py
Normal file
0
pyste/src/Pyste/__init__.py
Normal file
643
pyste/src/Pyste/declarations.py
Normal file
643
pyste/src/Pyste/declarations.py
Normal file
@@ -0,0 +1,643 @@
|
||||
'''
|
||||
Defines classes that represent declarations found in C++ header files.
|
||||
|
||||
'''
|
||||
|
||||
#==============================================================================
|
||||
# Declaration
|
||||
#==============================================================================
|
||||
class Declaration(object):
|
||||
'''Base class for all declarations.
|
||||
@ivar name: The name of the declaration.
|
||||
@ivar namespace: The namespace of the declaration.
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
'''
|
||||
@type name: string
|
||||
@param name: The name of this declaration
|
||||
@type namespace: string
|
||||
@param namespace: the full namespace where this declaration resides.
|
||||
'''
|
||||
self.name = name
|
||||
self.namespace = namespace
|
||||
self.location = '', -1 # (filename, line)
|
||||
self.incomplete = False
|
||||
self.is_unique = True
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'''
|
||||
Returns the full qualified name: "boost::inner::Test"
|
||||
@rtype: string
|
||||
@return: The full name of the declaration.
|
||||
'''
|
||||
namespace = self.namespace or ''
|
||||
if namespace and not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + self.name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '<Declaration %s at %s>' % (self.FullName(), id(self))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return 'Declaration of %s' % self.FullName()
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Class
|
||||
#==============================================================================
|
||||
class Class(Declaration):
|
||||
'''
|
||||
Represents a C++ class or struct. Iteration through it yields its members.
|
||||
|
||||
@type abstract: bool
|
||||
@ivar abstract: if the class has any abstract methods.
|
||||
|
||||
@type bases: tuple
|
||||
@ivar bases: tuple with L{Base} instances, representing the most direct
|
||||
inheritance.
|
||||
|
||||
@type hierarchy: list
|
||||
@ivar hierarchy: a list of tuples of L{Base} instances, representing
|
||||
the entire hierarchy tree of this object. The first tuple is the parent
|
||||
classes, and the other ones go up in the hierarchy.
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace, members, abstract):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.__members = members
|
||||
self.__member_names = {}
|
||||
self.abstract = abstract
|
||||
self.bases = ()
|
||||
self.hierarchy = ()
|
||||
self.operator = {}
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
'''iterates through the class' members.
|
||||
'''
|
||||
return iter(self.__members)
|
||||
|
||||
|
||||
def Constructors(self, publics_only=True):
|
||||
'''Returns a list of the constructors for this class.
|
||||
@rtype: list
|
||||
'''
|
||||
constructors = []
|
||||
for member in self:
|
||||
if isinstance(member, Constructor):
|
||||
if publics_only and member.visibility != Scope.public:
|
||||
continue
|
||||
constructors.append(member)
|
||||
return constructors
|
||||
|
||||
|
||||
def HasCopyConstructor(self):
|
||||
'''Returns true if this class has a public copy constructor.
|
||||
@rtype: bool
|
||||
'''
|
||||
for cons in self.Constructors():
|
||||
if cons.IsCopy():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def HasDefaultConstructor(self):
|
||||
'''Returns true if this class has a public default constructor.
|
||||
@rtype: bool
|
||||
'''
|
||||
for cons in self.Constructors():
|
||||
if cons.IsDefault():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def AddMember(self, member):
|
||||
if member.name in self.__member_names:
|
||||
member.is_unique = False
|
||||
for m in self:
|
||||
if m.name == member.name:
|
||||
m.is_unique = False
|
||||
else:
|
||||
member.is_unique = True
|
||||
self.__member_names[member.name] = 1
|
||||
self.__members.append(member)
|
||||
if isinstance(member, ClassOperator):
|
||||
self.operator[member.name] = member
|
||||
|
||||
|
||||
def ValidMemberTypes():
|
||||
return (NestedClass, Method, Constructor, Destructor, ClassVariable,
|
||||
ClassOperator, ConverterOperator, ClassEnumeration)
|
||||
ValidMemberTypes = staticmethod(ValidMemberTypes)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# NestedClass
|
||||
#==============================================================================
|
||||
class NestedClass(Class):
|
||||
'''The declaration of a class/struct inside another class/struct.
|
||||
|
||||
@type class: string
|
||||
@ivar class: fullname of the class where this class is contained.
|
||||
|
||||
@type visibility: L{Scope}
|
||||
@ivar visibility: the visibility of this class.
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, visib, members, abstract):
|
||||
Class.__init__(self, name, None, members, abstract)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'''The full name of this class, like ns::outer::inner.
|
||||
@rtype: string
|
||||
'''
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Scope
|
||||
#==============================================================================
|
||||
class Scope:
|
||||
'''Used to represent the visibility of various members inside a class.
|
||||
@cvar public: public visibility
|
||||
@cvar private: private visibility
|
||||
@cvar protected: protected visibility
|
||||
'''
|
||||
public = 'public'
|
||||
private = 'private'
|
||||
protected = 'protected'
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Base
|
||||
#==============================================================================
|
||||
class Base:
|
||||
'''Represents a base class of another class.
|
||||
@ivar _name: the full name of the base class.
|
||||
@ivar _visibility: the visibility of the derivation.
|
||||
'''
|
||||
|
||||
def __init__(self, name, visibility=Scope.public):
|
||||
self.name = name
|
||||
self.visibility = visibility
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Function
|
||||
#==============================================================================
|
||||
class Function(Declaration):
|
||||
'''The declaration of a function.
|
||||
@ivar _result: instance of L{Type} or None.
|
||||
@ivar _parameters: list of L{Type} instances.
|
||||
@ivar _throws: exception specifiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace, result, params, throws=None):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
self.result = result
|
||||
# the parameters: instances of Type
|
||||
self.parameters = params
|
||||
# the exception specification
|
||||
self.throws = throws
|
||||
|
||||
|
||||
def Exceptions(self):
|
||||
if self.throws is None:
|
||||
return ""
|
||||
else:
|
||||
return " throw(%s)" % ', '.join (self.throws)
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
'''Returns a declaration of a pointer to this function.
|
||||
@param force: If True, returns a complete pointer declaration regardless
|
||||
if this function is unique or not.
|
||||
'''
|
||||
if self.is_unique and not force:
|
||||
return '&%s' % self.FullName()
|
||||
else:
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
return '(%s (*)(%s))&%s' % (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)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Operator
|
||||
#==============================================================================
|
||||
class Operator(Function):
|
||||
'''The declaration of a custom operator. Its name is the same as the
|
||||
operator name in C++, ie, the name of the declaration "operator+(..)" is
|
||||
"+".
|
||||
'''
|
||||
|
||||
def FullName(self):
|
||||
namespace = self.namespace or ''
|
||||
if not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + 'operator' + self.name
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Method
|
||||
#==============================================================================
|
||||
class Method(Function):
|
||||
'''The declaration of a method.
|
||||
|
||||
@ivar _visibility: the visibility of this method.
|
||||
@ivar _virtual: if this method is declared as virtual.
|
||||
@ivar _abstract: if this method is virtual but has no default implementation.
|
||||
@ivar _static: if this method is static.
|
||||
@ivar _class: the full name of the class where this method was declared.
|
||||
@ivar _const: if this method is declared as const.
|
||||
@ivar _throws: list of exception specificiers or None
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const, throws=None):
|
||||
Function.__init__(self, name, None, result, params, throws)
|
||||
self.visibility = visib
|
||||
self.virtual = virtual
|
||||
self.abstract = abstract
|
||||
self.static = static
|
||||
self.class_ = class_
|
||||
self.const = const
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::' + self.name
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
'''Returns a declaration of a pointer to this member function.
|
||||
@param force: If True, returns a complete pointer declaration regardless
|
||||
if this function is unique or not.
|
||||
'''
|
||||
if self.static:
|
||||
# static methods are like normal functions
|
||||
return Function.PointerDeclaration(self, force)
|
||||
if self.is_unique and not force:
|
||||
return '&%s' % self.FullName()
|
||||
else:
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s%s)&%s' %\
|
||||
(result, self.class_, params, const, self.Exceptions(), self.FullName())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Constructor
|
||||
#==============================================================================
|
||||
class Constructor(Method):
|
||||
'''A class' constructor.
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, params, visib):
|
||||
Method.__init__(self, name, class_, None, params, visib, False, False, False, False)
|
||||
|
||||
|
||||
def IsDefault(self):
|
||||
'''Returns True if this constructor is a default constructor.
|
||||
'''
|
||||
return len(self.parameters) == 0 and self.visibility == Scope.public
|
||||
|
||||
|
||||
def IsCopy(self):
|
||||
'''Returns True if this constructor is a copy constructor.
|
||||
'''
|
||||
if len(self.parameters) != 1:
|
||||
return False
|
||||
param = self.parameters[0]
|
||||
class_as_param = self.parameters[0].name == self.class_
|
||||
param_reference = isinstance(param, ReferenceType)
|
||||
is_public = self.visibility = Scope.public
|
||||
return param_reference and class_as_param and param.const and is_public
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Destructor
|
||||
#==============================================================================
|
||||
class Destructor(Method):
|
||||
'The destructor of a class.'
|
||||
|
||||
def __init__(self, name, class_, visib, virtual):
|
||||
Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False)
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::~' + self.name
|
||||
|
||||
|
||||
def PointerDeclaration(self, force=False):
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassOperator
|
||||
#==============================================================================
|
||||
class ClassOperator(Method):
|
||||
'A custom operator in a class.'
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::operator ' + self.name
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ConverterOperator
|
||||
#==============================================================================
|
||||
class ConverterOperator(ClassOperator):
|
||||
'An operator in the form "operator OtherClass()".'
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::operator ' + self.result.FullName()
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Type
|
||||
#==============================================================================
|
||||
class Type(Declaration):
|
||||
'''Represents the type of a variable or parameter.
|
||||
@ivar _const: if the type is constant.
|
||||
@ivar _default: if this type has a default value associated with it.
|
||||
@ivar _volatile: if this type was declared with the keyword volatile.
|
||||
@ivar _restricted: if this type was declared with the keyword restricted.
|
||||
@ivar _suffix: Suffix to get the full type name. '*' for pointers, for
|
||||
example.
|
||||
'''
|
||||
|
||||
def __init__(self, name, const=False, default=None, suffix=''):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
self.const = const
|
||||
# used when the Type is a function argument
|
||||
self.default = default
|
||||
self.volatile = False
|
||||
self.restricted = False
|
||||
self.suffix = suffix
|
||||
|
||||
def __repr__(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return '<Type ' + const + self.name + '>'
|
||||
|
||||
|
||||
def FullName(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return const + self.name + self.suffix
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ArrayType
|
||||
#==============================================================================
|
||||
class ArrayType(Type):
|
||||
'''Represents an array.
|
||||
@ivar min: the lower bound of the array, usually 0. Can be None.
|
||||
@ivar max: the upper bound of the array. Can be None.
|
||||
'''
|
||||
|
||||
def __init__(self, name, const, min, max):
|
||||
'min and max can be None.'
|
||||
Type.__init__(self, name, const)
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ReferenceType
|
||||
#==============================================================================
|
||||
class ReferenceType(Type):
|
||||
'''A reference type.'''
|
||||
|
||||
def __init__(self, name, const=False, default=None, expandRef=True, suffix=''):
|
||||
Type.__init__(self, name, const, default)
|
||||
if expandRef:
|
||||
self.suffix = suffix + '&'
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# PointerType
|
||||
#==============================================================================
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, expandPointer=False, suffix=''):
|
||||
Type.__init__(self, name, const, default)
|
||||
if expandPointer:
|
||||
self.suffix = suffix + '*'
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FundamentalType
|
||||
#==============================================================================
|
||||
class FundamentalType(Type):
|
||||
'One of the fundamental types, like int, void, etc.'
|
||||
|
||||
def __init__(self, name, const=False, default=None):
|
||||
Type.__init__(self, name, const, default)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionType
|
||||
#==============================================================================
|
||||
class FunctionType(Type):
|
||||
'''A pointer to a function.
|
||||
@ivar _result: the return value
|
||||
@ivar _parameters: a list of Types, indicating the parameters of the function.
|
||||
@ivar _name: the name of the function.
|
||||
'''
|
||||
|
||||
def __init__(self, result, parameters):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
self.parameters = parameters
|
||||
self.name = self.FullName()
|
||||
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (*)' % self.result.FullName()
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MethodType
|
||||
#==============================================================================
|
||||
class MethodType(FunctionType):
|
||||
'''A pointer to a member function of a class.
|
||||
@ivar _class: The fullname of the class that the method belongs to.
|
||||
'''
|
||||
|
||||
def __init__(self, result, parameters, class_):
|
||||
self.class_ = class_
|
||||
FunctionType.__init__(self, result, parameters)
|
||||
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (%s::*)' % (self.result.FullName(), self.class_)
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Variable
|
||||
#==============================================================================
|
||||
class Variable(Declaration):
|
||||
'''Represents a global variable.
|
||||
|
||||
@type _type: L{Type}
|
||||
@ivar _type: The type of the variable.
|
||||
'''
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.type = type
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassVariable
|
||||
#==============================================================================
|
||||
class ClassVariable(Variable):
|
||||
'''Represents a class variable.
|
||||
|
||||
@type _visibility: L{Scope}
|
||||
@ivar _visibility: The visibility of this variable within the class.
|
||||
|
||||
@type _static: bool
|
||||
@ivar _static: Indicates if the variable is static.
|
||||
|
||||
@ivar _class: Full name of the class that this variable belongs to.
|
||||
'''
|
||||
|
||||
def __init__(self, type, name, class_, visib, static):
|
||||
Variable.__init__(self, type, name, None)
|
||||
self.visibility = visib
|
||||
self.static = static
|
||||
self.class_ = class_
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::' + self.name
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Enumeration
|
||||
#==============================================================================
|
||||
class Enumeration(Declaration):
|
||||
'''Represents an enum.
|
||||
|
||||
@type _values: dict of str => int
|
||||
@ivar _values: holds the values for this enum.
|
||||
'''
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.values = {} # dict of str => int
|
||||
|
||||
|
||||
def ValueFullName(self, name):
|
||||
'''Returns the full name for a value in the enum.
|
||||
'''
|
||||
assert name in self.values
|
||||
namespace = self.namespace
|
||||
if namespace:
|
||||
namespace += '::'
|
||||
return namespace + name
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassEnumeration
|
||||
#==============================================================================
|
||||
class ClassEnumeration(Enumeration):
|
||||
'''Represents an enum inside a class.
|
||||
|
||||
@ivar _class: The full name of the class where this enum belongs.
|
||||
@ivar _visibility: The visibility of this enum inside his class.
|
||||
'''
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Enumeration.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
def ValueFullName(self, name):
|
||||
assert name in self.values
|
||||
return '%s::%s' % (self.class_, name)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Typedef
|
||||
#==============================================================================
|
||||
class Typedef(Declaration):
|
||||
'''A Typedef declaration.
|
||||
|
||||
@type _type: L{Type}
|
||||
@ivar _type: The type of the typedef.
|
||||
|
||||
@type _visibility: L{Scope}
|
||||
@ivar _visibility: The visibility of this typedef.
|
||||
'''
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.type = type
|
||||
self.visibility = Scope.public
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Unknown
|
||||
#==============================================================================
|
||||
class Unknown(Declaration):
|
||||
'''A declaration that Pyste does not know how to handle.
|
||||
'''
|
||||
|
||||
def __init__(self, name):
|
||||
Declaration.__init__(self, name, None)
|
||||
5
pyste/src/Pyste/exporters.py
Normal file
5
pyste/src/Pyste/exporters.py
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
# a list of Exporter instances
|
||||
exporters = []
|
||||
|
||||
current_interface = None # the current interface file being processed
|
||||
@@ -41,7 +41,7 @@ def HandlePolicy(function, policy):
|
||||
|
||||
def IsString(type):
|
||||
'Return True if the Type instance can be considered a string'
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
return type.FullName() == 'const char*'
|
||||
|
||||
def IsPyObject(type):
|
||||
return type.FullName() == '_object *' # internal name of PyObject
|
||||
@@ -68,24 +68,15 @@ def HandlePolicy(function, policy):
|
||||
return policy
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# WarnForwardDeclarations
|
||||
# EspecializeTypeID
|
||||
#==============================================================================
|
||||
def WarnForwardDeclarations(function):
|
||||
'''Checks if any of the parameters or the result of the function are
|
||||
incomplete types.'''
|
||||
|
||||
types = [function.result] + function.parameters
|
||||
types = [x for x in types if x]
|
||||
for type in types:
|
||||
if type.incomplete:
|
||||
msg = '---> Error: %s is forward declared. Please include the ' \
|
||||
'appropriate header with its definition' % type.name
|
||||
# disable this for now... it was reporting too many false
|
||||
# forward declarations to be useful
|
||||
if 0 and msg not in _printed_warnings:
|
||||
print msg
|
||||
print
|
||||
_printed_warnings[msg] = 1
|
||||
|
||||
_exported_type_ids = {}
|
||||
def EspecializeTypeID(typename):
|
||||
global _exported_type_ids
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)\n' % typename
|
||||
if macro not in _exported_type_ids:
|
||||
_exported_type_ids[macro] = 1
|
||||
return macro
|
||||
else:
|
||||
return None
|
||||
@@ -7,6 +7,7 @@ from IncludeExporter import IncludeExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
from VarExporter import VarExporter
|
||||
from CodeExporter import CodeExporter
|
||||
from exporterutils import FunctionWrapper
|
||||
from utils import makeid
|
||||
|
||||
@@ -58,7 +59,9 @@ class FunctionInfo(DeclarationInfo):
|
||||
self._Attribute('exclude', False)
|
||||
# create a FunctionExporter
|
||||
exporter = FunctionExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -73,7 +76,9 @@ class ClassInfo(DeclarationInfo):
|
||||
self._Attribute('exclude', False)
|
||||
# create a ClassExporter
|
||||
exporter = ClassExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -85,7 +90,9 @@ class IncludeInfo(DeclarationInfo):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = IncludeExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -134,7 +141,9 @@ class EnumInfo(DeclarationInfo):
|
||||
self._Attribute('include', include)
|
||||
self._Attribute('exclude', False)
|
||||
exporter = EnumExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -146,7 +155,9 @@ class HeaderInfo(DeclarationInfo):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = HeaderExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -159,9 +170,26 @@ class VarInfo(DeclarationInfo):
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
exporter = VarExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CodeInfo
|
||||
#==============================================================================
|
||||
class CodeInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, code, section):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('code', code)
|
||||
self._Attribute('section', section)
|
||||
exporter = CodeExporter(InfoWrapper(self))
|
||||
if exporter not in exporters.exporters:
|
||||
exporters.exporters.append(exporter)
|
||||
exporter.interface_file = exporters.current_interface
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# InfoWrapper
|
||||
#==============================================================================
|
||||
@@ -209,9 +237,17 @@ def use_shared_ptr(info):
|
||||
def use_auto_ptr(info):
|
||||
info._Attribute('smart_ptr', 'std::auto_ptr< %s >')
|
||||
|
||||
def holder(info, function):
|
||||
msg = "Expected a callable that accepts one string argument."
|
||||
assert callable(function), msg
|
||||
info._Attribute('holder', function)
|
||||
|
||||
def add_method(info, name, rename=None):
|
||||
added = info._Attribute('__added__')
|
||||
if added is None:
|
||||
info._Attribute('__added__', [(name, rename)])
|
||||
else:
|
||||
added.append((name, rename))
|
||||
|
||||
def final(info):
|
||||
info._Attribute('no_override', True)
|
||||
374
pyste/src/Pyste/pyste.py
Normal file
374
pyste/src/Pyste/pyste.py
Normal file
@@ -0,0 +1,374 @@
|
||||
"""
|
||||
Pyste version %s
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> The name of the module that will be generated;
|
||||
defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> Add an include path
|
||||
-D <symbol> Define symbol
|
||||
--multiple Create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out=<name> Specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using Do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> Set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug Writes the xml for each file parsed in the current
|
||||
directory
|
||||
--cache-dir=<dir> Directory for cache files (speeds up future runs)
|
||||
--only-create-cache Recreates all caches (doesn't generate code).
|
||||
--generate-main Generates the _main.cpp file (in multiple mode)
|
||||
-h, --help Print this help and exit
|
||||
-v, --version Print version information
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import exporters
|
||||
import SingleCodeUnit
|
||||
import MultipleCodeUnit
|
||||
import infos
|
||||
import exporterutils
|
||||
import settings
|
||||
import gc
|
||||
import sys
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
import time
|
||||
from declarations import Typedef
|
||||
|
||||
__version__ = '0.9.15'
|
||||
|
||||
def RecursiveIncludes(include):
|
||||
'Return a list containg the include dir and all its subdirectories'
|
||||
dirs = [include]
|
||||
def visit(arg, dir, names):
|
||||
# ignore CVS dirs
|
||||
if os.path.split(dir)[1] != 'CVS':
|
||||
dirs.append(dir)
|
||||
os.path.walk(include, visit, None)
|
||||
return dirs
|
||||
|
||||
|
||||
def GetDefaultIncludes():
|
||||
if 'INCLUDE' in os.environ:
|
||||
include = os.environ['INCLUDE']
|
||||
return include.split(os.pathsep)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def ProcessIncludes(includes):
|
||||
if sys.platform == 'win32':
|
||||
index = 0
|
||||
for include in includes:
|
||||
includes[index] = include.replace('\\', '/')
|
||||
index += 1
|
||||
|
||||
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__ % __version__
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
options, files = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'R:I:D:vh',
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'cache-dir=',
|
||||
'only-create-cache', 'version', 'generate-main', 'help'])
|
||||
except getopt.GetoptError, e:
|
||||
print
|
||||
print 'ERROR:', e
|
||||
Usage()
|
||||
|
||||
includes = GetDefaultIncludes()
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
multiple = False
|
||||
cache_dir = None
|
||||
create_cache = False
|
||||
generate_main = False
|
||||
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
elif opt == '-D':
|
||||
defines.append(value)
|
||||
elif opt == '-R':
|
||||
includes.extend(RecursiveIncludes(value))
|
||||
elif opt == '--module':
|
||||
module = value
|
||||
elif opt == '--out':
|
||||
out = value
|
||||
elif opt == '--no-using':
|
||||
settings.namespaces.python = 'boost::python::'
|
||||
settings.USING_BOOST_NS = False
|
||||
elif opt == '--pyste-ns':
|
||||
settings.namespaces.pyste = value + '::'
|
||||
elif opt == '--debug':
|
||||
settings.DEBUG = True
|
||||
elif opt == '--multiple':
|
||||
multiple = True
|
||||
elif opt == '--cache-dir':
|
||||
cache_dir = value
|
||||
elif opt == '--only-create-cache':
|
||||
create_cache = True
|
||||
elif opt in ['-h', '--help']:
|
||||
Usage()
|
||||
elif opt in ['-v', '--version']:
|
||||
print 'Pyste version %s' % __version__
|
||||
sys.exit(2)
|
||||
elif opt == '--generate-main':
|
||||
generate_main = True
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
|
||||
if not files:
|
||||
Usage()
|
||||
if not module:
|
||||
module = os.path.splitext(files[0])[0]
|
||||
if not out:
|
||||
out = module
|
||||
if not multiple:
|
||||
out += '.cpp'
|
||||
for file in files:
|
||||
d = os.path.dirname(os.path.abspath(file))
|
||||
if d not in sys.path:
|
||||
sys.path.append(d)
|
||||
|
||||
if create_cache and not cache_dir:
|
||||
print 'Error: Use --cache-dir to indicate where to create the cache files!'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
if generate_main and not multiple:
|
||||
print 'Error: --generate-main only valid in multiple mode.'
|
||||
Usage()
|
||||
sys.exit(3)
|
||||
|
||||
ProcessIncludes(includes)
|
||||
return includes, defines, module, out, files, multiple, cache_dir, create_cache, generate_main
|
||||
|
||||
|
||||
def CreateContext():
|
||||
'create the context where a interface file will be executed'
|
||||
context = {}
|
||||
context['Import'] = ExecuteInterface
|
||||
# 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
|
||||
context['Var'] = infos.VarInfo
|
||||
# functions
|
||||
context['rename'] = infos.rename
|
||||
context['set_policy'] = infos.set_policy
|
||||
context['exclude'] = infos.exclude
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
context['holder'] = infos.holder
|
||||
context['add_method'] = infos.add_method
|
||||
context['final'] = infos.final
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
context['return_value_policy'] = return_value_policy
|
||||
context['reference_existing_object'] = reference_existing_object
|
||||
context['copy_const_reference'] = copy_const_reference
|
||||
context['copy_non_const_reference'] = copy_non_const_reference
|
||||
context['return_opaque_pointer'] = return_opaque_pointer
|
||||
context['manage_new_object'] = manage_new_object
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
context['header_code'] = lambda code: infos.CodeInfo(code, 'include')
|
||||
context['declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration')
|
||||
context['global_declaration_code'] = lambda code: infos.CodeInfo(code, 'declaration-outside')
|
||||
context['module_code'] = lambda code: infos.CodeInfo(code, 'module')
|
||||
return context
|
||||
|
||||
|
||||
def Begin():
|
||||
# parse arguments
|
||||
includes, defines, module, out, interfaces, multiple, cache_dir, create_cache, generate_main = ParseArguments()
|
||||
# run pyste scripts
|
||||
for interface in interfaces:
|
||||
ExecuteInterface(interface)
|
||||
# create the parser
|
||||
parser = CppParser(includes, defines, cache_dir)
|
||||
try:
|
||||
if not create_cache:
|
||||
if not generate_main:
|
||||
return GenerateCode(parser, module, out, interfaces, multiple)
|
||||
else:
|
||||
return GenerateMain(module, out, OrderInterfaces(interfaces))
|
||||
else:
|
||||
return CreateCaches(parser)
|
||||
finally:
|
||||
parser.Close()
|
||||
|
||||
|
||||
def CreateCaches(parser):
|
||||
# There is one cache file per interface so we organize the headers
|
||||
# by interfaces. For each interface collect the tails from the
|
||||
# exporters sharing the same header.
|
||||
tails = JoinTails(exporters.exporters)
|
||||
|
||||
# now for each interface file take each header, and using the tail
|
||||
# get the declarations and cache them.
|
||||
for interface, header in tails:
|
||||
tail = tails[(interface, header)]
|
||||
declarations = parser.ParseWithGCCXML(header, tail)
|
||||
cachefile = parser.CreateCache(header, interface, tail, declarations)
|
||||
print 'Cached', cachefile
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
_imported_count = {} # interface => count
|
||||
|
||||
def ExecuteInterface(interface):
|
||||
old_interface = exporters.current_interface
|
||||
if not os.path.exists(interface):
|
||||
if old_interface and os.path.exists(old_interface):
|
||||
d = os.path.dirname(old_interface)
|
||||
interface = os.path.join(d, interface)
|
||||
if not os.path.exists(interface):
|
||||
raise IOError, "Cannot find interface file %s."%interface
|
||||
|
||||
_imported_count[interface] = _imported_count.get(interface, 0) + 1
|
||||
exporters.current_interface = interface
|
||||
context = CreateContext()
|
||||
execfile(interface, context)
|
||||
exporters.current_interface = old_interface
|
||||
|
||||
|
||||
def JoinTails(exports):
|
||||
'''Returns a dict of {(interface, header): tail}, where tail is the
|
||||
joining of all tails of all exports for the header.
|
||||
'''
|
||||
tails = {}
|
||||
for export in exports:
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
tail = export.Tail() or ''
|
||||
if (interface, header) in tails:
|
||||
all_tails = tails[(interface,header)]
|
||||
all_tails += '\n' + tail
|
||||
tails[(interface, header)] = all_tails
|
||||
else:
|
||||
tails[(interface, header)] = tail
|
||||
|
||||
return tails
|
||||
|
||||
|
||||
|
||||
def OrderInterfaces(interfaces):
|
||||
interfaces_order = [(_imported_count[x], x) for x in interfaces]
|
||||
interfaces_order.sort()
|
||||
interfaces_order.reverse()
|
||||
return [x for _, x in interfaces_order]
|
||||
|
||||
|
||||
|
||||
def GenerateMain(module, out, interfaces):
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
codeunit.GenerateMain(interfaces)
|
||||
return 0
|
||||
|
||||
|
||||
def GenerateCode(parser, module, out, interfaces, multiple):
|
||||
# prepare to generate the wrapper code
|
||||
if multiple:
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
else:
|
||||
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
|
||||
# stop referencing the exporters here
|
||||
exports = exporters.exporters
|
||||
exporters.exporters = None
|
||||
exported_names = dict([(x.Name(), None) for x in exports])
|
||||
|
||||
# order the exports
|
||||
interfaces_order = OrderInterfaces(interfaces)
|
||||
order = {}
|
||||
for export in exports:
|
||||
if export.interface_file in order:
|
||||
order[export.interface_file].append(export)
|
||||
else:
|
||||
order[export.interface_file] = [export]
|
||||
exports = []
|
||||
for interface in interfaces_order:
|
||||
exports.extend(order[interface])
|
||||
del order
|
||||
del interfaces_order
|
||||
|
||||
# now generate the code in the correct order
|
||||
#print exported_names
|
||||
tails = JoinTails(exports)
|
||||
for i in xrange(len(exports)):
|
||||
export = exports[i]
|
||||
interface = export.interface_file
|
||||
header = export.Header()
|
||||
if header:
|
||||
tail = tails[(interface, header)]
|
||||
declarations, parsed_header = parser.Parse(header, interface, tail)
|
||||
else:
|
||||
declarations = []
|
||||
parsed_header = None
|
||||
ExpandTypedefs(declarations, exported_names)
|
||||
export.SetDeclarations(declarations)
|
||||
export.SetParsedHeader(parsed_header)
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.interface_file, export.Name())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
# force collect of cyclic references
|
||||
exports[i] = None
|
||||
del declarations
|
||||
del export
|
||||
gc.collect()
|
||||
# finally save the code unit
|
||||
codeunit.Save()
|
||||
if not multiple:
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def ExpandTypedefs(declarations, exported_names):
|
||||
'''Check if the names in exported_names are a typedef, and add the real class
|
||||
name in the dict.
|
||||
'''
|
||||
for name in exported_names.keys():
|
||||
for decl in declarations:
|
||||
if isinstance(decl, Typedef):
|
||||
exported_names[decl.type.FullName()] = None
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if possible'
|
||||
try:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
except: pass
|
||||
|
||||
|
||||
def main():
|
||||
start = time.clock()
|
||||
UsePsyco()
|
||||
status = Begin()
|
||||
print '%0.2f seconds' % (time.clock()-start)
|
||||
sys.exit(status)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import generators
|
||||
import string
|
||||
import sys
|
||||
|
||||
#==============================================================================
|
||||
# enumerate
|
||||
@@ -19,6 +20,8 @@ _valid_chars = dict(zip(_valid_chars, _valid_chars))
|
||||
|
||||
def makeid(name):
|
||||
'Returns the name as a valid identifier'
|
||||
if type(name) != str:
|
||||
print type(name), name
|
||||
newname = []
|
||||
for char in name:
|
||||
if char not in _valid_chars:
|
||||
@@ -45,3 +48,24 @@ def remove_duplicated_lines(text):
|
||||
def left_equals(s):
|
||||
s = '// %s ' % s
|
||||
return s + ('='*(80-len(s))) + '\n'
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# post_mortem
|
||||
#==============================================================================
|
||||
def post_mortem():
|
||||
|
||||
def info(type, value, tb):
|
||||
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
|
||||
# we are in interactive mode or we don't have a tty-like
|
||||
# device, so we call the default hook
|
||||
sys.__excepthook__(type, value, tb)
|
||||
else:
|
||||
import traceback, pdb
|
||||
# we are NOT in interactive mode, print the exception...
|
||||
traceback.print_exception(type, value, tb)
|
||||
print
|
||||
# ...then start the debugger in post-mortem mode.
|
||||
pdb.pm()
|
||||
|
||||
sys.excepthook = info
|
||||
@@ -1,554 +0,0 @@
|
||||
'''
|
||||
Module declarations
|
||||
|
||||
Defines classes that represent declarations found in C++ header files.
|
||||
|
||||
'''
|
||||
|
||||
class Declaration(object):
|
||||
'Represents a basic declaration.'
|
||||
|
||||
__slots__ = 'name namespace location incomplete'.split()
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
# the declaration name
|
||||
self.name = name
|
||||
# all the namespaces, separated by '::' = 'boost::inner'
|
||||
self.namespace = namespace
|
||||
# tuple (filename, line)
|
||||
self.location = '', -1
|
||||
# if a declaration is incomplete it means that it was
|
||||
# forward declared
|
||||
self.incomplete = False
|
||||
|
||||
|
||||
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.'
|
||||
|
||||
__slots__= 'members abstract bases _members_count'.split()
|
||||
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.'
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
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.'
|
||||
|
||||
__slots__= 'name visibility'.split()
|
||||
|
||||
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.'
|
||||
|
||||
__slots__= 'result parameters'.split()
|
||||
|
||||
def __init__(self, name, namespace, result, params):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
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)
|
||||
|
||||
|
||||
def Copy(self):
|
||||
return self.__class__(
|
||||
self.name, self.namespace, self.result, self.params[:])
|
||||
|
||||
|
||||
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.'
|
||||
|
||||
__slots__= 'visibility virtual abstract static class_ const'.split()
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
|
||||
Function.__init__(self, name, None, result, params)
|
||||
self.visibility = visib
|
||||
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'
|
||||
if self.static:
|
||||
# static methods are like normal functions
|
||||
return Function.PointerDeclaration(self)
|
||||
else:
|
||||
# using syntax of methods
|
||||
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())
|
||||
|
||||
|
||||
def Copy(self):
|
||||
return self.__class__(
|
||||
self.name,
|
||||
self.class_,
|
||||
self.result,
|
||||
self.parameters[:],
|
||||
self.visibility,
|
||||
self.virtual,
|
||||
self.abstract,
|
||||
self.static,
|
||||
self.const)
|
||||
|
||||
|
||||
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.FullName()
|
||||
|
||||
|
||||
|
||||
class Type(Declaration):
|
||||
'Represents a type.'
|
||||
|
||||
__slots__= 'const default volatile restricted incomplete'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
self.const = const
|
||||
# used when the Type is a function argument
|
||||
self.default = default
|
||||
self.volatile = False
|
||||
self.restricted = False
|
||||
self.incomplete = incomplete
|
||||
|
||||
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
|
||||
|
||||
|
||||
def Copy(self):
|
||||
t = self.__class__(self.name, self.const, self.default, self.incomplete)
|
||||
t.volatile = self.volatile
|
||||
t.restricted = self.restricted
|
||||
return t
|
||||
|
||||
|
||||
class ArrayType(Type):
|
||||
'Represents an array.'
|
||||
|
||||
__slots__= 'min max'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
'min and max can be None.'
|
||||
Type.__init__(self, name, const)
|
||||
self.min = None
|
||||
self.max = None
|
||||
|
||||
def Copy(self):
|
||||
t = Type.Copy(self)
|
||||
t.min = self.min
|
||||
t.max = self.max
|
||||
return t
|
||||
|
||||
|
||||
|
||||
class ReferenceType(Type):
|
||||
'A reference type.'
|
||||
|
||||
__slots__= 'expand'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandRef=True):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
self.expand = expandRef
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'expand is False for function pointers'
|
||||
expand = ' &'
|
||||
if not self.expand:
|
||||
expand = ''
|
||||
return Type.FullName(self) + expand
|
||||
|
||||
|
||||
def Copy(self):
|
||||
t = Type.Copy(self)
|
||||
t.expand = self.expand
|
||||
return t
|
||||
|
||||
|
||||
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
__slots__= 'expand'.split()
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandPointer=False):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
self.expand = expandPointer
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'expand is False for function pointer'
|
||||
expand = ' *'
|
||||
if not self.expand:
|
||||
expand = ''
|
||||
return Type.FullName(self) + expand
|
||||
|
||||
def Copy(self):
|
||||
t = Type.Copy(self)
|
||||
t.expand = self.expand
|
||||
return t
|
||||
|
||||
|
||||
|
||||
class FundamentalType(Type):
|
||||
'One of the fundamental types (int, void...).'
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
|
||||
|
||||
|
||||
class FunctionType(Type):
|
||||
'A pointer to a function.'
|
||||
|
||||
__slots__= 'result parameters name'.split()
|
||||
|
||||
def __init__(self, result, parameters):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
self.parameters = parameters
|
||||
self.name = self.FullName()
|
||||
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (*)' % self.result.FullName()
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
def Copy(self):
|
||||
return FunctionType(self.result, self.parameters[:])
|
||||
|
||||
|
||||
class MethodType(FunctionType):
|
||||
'A pointer to a member function of a class.'
|
||||
|
||||
__slots__= 'result parameters class_ name'.split()
|
||||
|
||||
def __init__(self, result, parameters, class_):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
self.parameters = parameters
|
||||
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
|
||||
|
||||
def Copy(self):
|
||||
return MethodType(self.result, self.parameters[:], self.class_)
|
||||
|
||||
|
||||
class Variable(Declaration):
|
||||
'Represents a global variable.'
|
||||
|
||||
__slots__= 'type'.split()
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# instance of Type
|
||||
self.type = type
|
||||
|
||||
|
||||
|
||||
class ClassVariable(Variable):
|
||||
'Represents a class variable.'
|
||||
|
||||
__slots__= 'visibility static class_'.split()
|
||||
|
||||
def __init__(self, type, name, class_, visib, static):
|
||||
Variable.__init__(self, type, name, None)
|
||||
self.visibility = visib
|
||||
self.static = static
|
||||
self.class_ = class_
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::' + self.name
|
||||
|
||||
|
||||
|
||||
class Enumeration(Declaration):
|
||||
|
||||
__slots__= 'values'.split()
|
||||
|
||||
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):
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
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):
|
||||
|
||||
__slots__= 'type visibility'.split()
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.type = type
|
||||
self.visibility = Scope.public
|
||||
|
||||
|
||||
class Union(Declaration):
|
||||
'Shallow declaration, because Unions are not supported yet'
|
||||
def __init__(self, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
|
||||
|
||||
class ClassUnion(Union):
|
||||
|
||||
__slots__= 'class_ visibility'.split()
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Union.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
def FullName(self):
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
# a list of Exporter instances
|
||||
exporters = []
|
||||
@@ -1,17 +0,0 @@
|
||||
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()
|
||||
@@ -1,204 +0,0 @@
|
||||
'''
|
||||
Pyste version %s
|
||||
|
||||
Usage:
|
||||
pyste [options] interface-files
|
||||
|
||||
where options are:
|
||||
--module=<name> the name of the module that will be generated.
|
||||
Defaults to the first interface filename, without
|
||||
the extension.
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug writes the xml for each file parsed in the current
|
||||
directory
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information
|
||||
'''
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import exporters
|
||||
import SingleCodeUnit
|
||||
import MultipleCodeUnit
|
||||
import infos
|
||||
import exporterutils
|
||||
import settings
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
import time
|
||||
|
||||
__VERSION__ = '0.9.2'
|
||||
|
||||
def RecursiveIncludes(include):
|
||||
'Return a list containg the include dir and all its subdirectories'
|
||||
dirs = [include]
|
||||
def visit(arg, dir, names):
|
||||
# ignore CVS dirs
|
||||
if os.path.split(dir)[1] != 'CVS':
|
||||
dirs.append(dir)
|
||||
os.path.walk(include, visit, None)
|
||||
return dirs
|
||||
|
||||
|
||||
def GetDefaultIncludes():
|
||||
if 'INCLUDE' in os.environ:
|
||||
include = os.environ['INCLUDE']
|
||||
return include.split(os.pathsep)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__ % __VERSION__
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
options, files = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'R:I:D:vh',
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'version', 'help'])
|
||||
except getopt.GetoptError, e:
|
||||
print
|
||||
print 'ERROR:', e
|
||||
Usage()
|
||||
includes = GetDefaultIncludes()
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
multiple = False
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
elif opt == '-D':
|
||||
defines.append(value)
|
||||
elif opt == '-R':
|
||||
includes.extend(RecursiveIncludes(value))
|
||||
elif opt == '--module':
|
||||
module = value
|
||||
elif opt == '--out':
|
||||
out = value
|
||||
elif opt == '--no-using':
|
||||
settings.namespaces.python = 'boost::python::'
|
||||
settings.USING_BOOST_NS = False
|
||||
elif opt == '--pyste-ns':
|
||||
settings.namespaces.pyste = value + '::'
|
||||
elif opt == '--debug':
|
||||
settings.DEBUG = True
|
||||
elif opt == '--multiple':
|
||||
multiple = True
|
||||
elif opt in ['-h', '--help']:
|
||||
Usage()
|
||||
elif opt in ['-v', '--version']:
|
||||
print 'Pyste version %s' % __VERSION__
|
||||
sys.exit(2)
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
|
||||
if not files:
|
||||
Usage()
|
||||
if not module:
|
||||
module = os.path.splitext(files[0])[0]
|
||||
if not out:
|
||||
out = module
|
||||
if not multiple:
|
||||
out += '.cpp'
|
||||
return includes, defines, module, out, files, multiple
|
||||
|
||||
|
||||
def CreateContext():
|
||||
'create the context where a interface file will 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
|
||||
context['Var'] = infos.VarInfo
|
||||
# functions
|
||||
context['rename'] = infos.rename
|
||||
context['set_policy'] = infos.set_policy
|
||||
context['exclude'] = infos.exclude
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
context['add_method'] = infos.add_method
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
context['return_value_policy'] = return_value_policy
|
||||
context['reference_existing_object'] = reference_existing_object
|
||||
context['copy_const_reference'] = copy_const_reference
|
||||
context['copy_non_const_reference'] = copy_non_const_reference
|
||||
context['return_opaque_pointer'] = return_opaque_pointer
|
||||
context['manage_new_object'] = manage_new_object
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
return context
|
||||
|
||||
|
||||
def Main():
|
||||
includes, defines, module, out, interfaces, multiple = 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
|
||||
if multiple:
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
else:
|
||||
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
|
||||
exported_names = []
|
||||
for export in exports:
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.Unit())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
exported_names.append(export.Name())
|
||||
codeunit.Save()
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if possible'
|
||||
try:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
except: pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start = time.clock()
|
||||
UsePsyco()
|
||||
status = Main()
|
||||
print '%0.2f seconds' % (time.clock()-start)
|
||||
sys.exit(status)
|
||||
@@ -1,5 +1,5 @@
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
sys.path.append('../src')
|
||||
import unittest
|
||||
import tempfile
|
||||
import os.path
|
||||
@@ -30,7 +30,7 @@ class Tester(unittest.TestCase):
|
||||
param,
|
||||
ReferenceType,
|
||||
class_.FullName(),
|
||||
'const %s &' % class_.FullName(),
|
||||
'const %s&' % class_.FullName(),
|
||||
True)
|
||||
self.assert_(method.IsCopy())
|
||||
|
||||
@@ -52,7 +52,6 @@ class ClassBaseTest(Tester):
|
||||
'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):
|
||||
@@ -72,7 +71,7 @@ class ClassBaseTest(Tester):
|
||||
self.TestType(param, FundamentalType, 'int', 'int', False)
|
||||
self.assertEqual(foo.namespace, None)
|
||||
self.assertEqual(
|
||||
foo.PointerDeclaration(), '(void (test::Base::*)(int) )&test::Base::foo')
|
||||
foo.PointerDeclaration(1), '(void (test::Base::*)(int) )&test::Base::foo')
|
||||
|
||||
def testX(self):
|
||||
'test the member x in class Base'
|
||||
@@ -105,11 +104,11 @@ class ClassBaseTest(Tester):
|
||||
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(param, ReferenceType, 'std::string', 'const std::string&', True)
|
||||
self.TestType(simple.result, FundamentalType, 'bool', 'bool', False)
|
||||
self.assertEqual(
|
||||
simple.PointerDeclaration(),
|
||||
'(bool (test::Base::*)(const std::string &) )&test::Base::simple')
|
||||
simple.PointerDeclaration(1),
|
||||
'(bool (test::Base::*)(const std::string&) )&test::Base::simple')
|
||||
|
||||
|
||||
def testZ(self):
|
||||
@@ -134,7 +133,6 @@ class ClassTemplateTest(Tester):
|
||||
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>'
|
||||
@@ -180,20 +178,20 @@ class FreeFuncTest(Tester):
|
||||
self.assertEqual(self.func.FullName(), 'test::FreeFunc')
|
||||
self.assertEqual(self.func.namespace, 'test')
|
||||
self.assertEqual(
|
||||
self.func.PointerDeclaration(),
|
||||
'(const test::Base & (*)(const std::string &, int))&test::FreeFunc')
|
||||
self.func.PointerDeclaration(1),
|
||||
'(const test::Base& (*)(const std::string&, int))&test::FreeFunc')
|
||||
|
||||
|
||||
def testResult(self):
|
||||
'test the return value of FreeFunc'
|
||||
res = self.func.result
|
||||
self.TestType(res, ReferenceType, 'test::Base', 'const test::Base &', True)
|
||||
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.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')
|
||||
|
||||
17
pyste/tests/abstract_test.h
Normal file
17
pyste/tests/abstract_test.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace abstract {
|
||||
|
||||
struct A {
|
||||
virtual ~A() {}
|
||||
virtual std::string f()=0;
|
||||
};
|
||||
|
||||
struct B: A {
|
||||
std::string f() { return "B::f"; }
|
||||
};
|
||||
|
||||
std::string call(A* a) { return a->f(); }
|
||||
|
||||
}
|
||||
3
pyste/tests/abstract_test.pyste
Normal file
3
pyste/tests/abstract_test.pyste
Normal file
@@ -0,0 +1,3 @@
|
||||
Class('abstract::A', 'abstract_test.h')
|
||||
Class('abstract::B', 'abstract_test.h')
|
||||
Function('abstract::call', 'abstract_test.h')
|
||||
22
pyste/tests/abstract_testUT.py
Normal file
22
pyste/tests/abstract_testUT.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import unittest
|
||||
from _abstract_test import *
|
||||
|
||||
class AbstractTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
class C(A):
|
||||
def f(self):
|
||||
return 'C::f'
|
||||
|
||||
a = A()
|
||||
b = B()
|
||||
c = C()
|
||||
self.assertRaises(RuntimeError, a.f)
|
||||
self.assertEqual(b.f(), 'B::f')
|
||||
self.assertEqual(call(b), 'B::f')
|
||||
self.assertEqual(c.f(), 'C::f')
|
||||
self.assertEqual(call(c), 'C::f')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -19,10 +19,12 @@ struct C
|
||||
return x+1;
|
||||
}
|
||||
|
||||
const std::string& name() { return _name; }
|
||||
void set_name(const std::string& name) { _name = name; }
|
||||
std::string _name;
|
||||
const std::string& get_name() { return name; }
|
||||
void set_name(const std::string& name) { this->name = name; }
|
||||
private:
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
// test data members
|
||||
static int static_value;
|
||||
static const int const_static_value;
|
||||
@@ -31,7 +33,10 @@ struct C
|
||||
const int const_value;
|
||||
|
||||
// test static functions
|
||||
static int mul(int x=2, int y=3) { return x*y; }
|
||||
static int mul(int x, int y) { return x*y; }
|
||||
static double mul(double x, double y) { return x*y; }
|
||||
|
||||
static int square(int x=2) { return x*x; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c)
|
||||
|
||||
@@ -57,9 +57,12 @@ class BasicExampleTest(unittest.TestCase):
|
||||
def test_mul(result, *args):
|
||||
self.assertEqual(C.mul(*args), result)
|
||||
self.assertEqual(c.mul(*args), result)
|
||||
test_mul(6)
|
||||
test_mul(3, 1)
|
||||
test_mul(16, 8, 2)
|
||||
test_mul(6.0, 2.0, 3.0)
|
||||
self.assertEqual(C.square(), 4)
|
||||
self.assertEqual(c.square(), 4)
|
||||
self.assertEqual(C.square(3), 9)
|
||||
self.assertEqual(c.square(3), 9)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
4
pyste/tests/code_test.h
Normal file
4
pyste/tests/code_test.h
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
struct A {
|
||||
int x;
|
||||
};
|
||||
9
pyste/tests/code_test.pyste
Normal file
9
pyste/tests/code_test.pyste
Normal file
@@ -0,0 +1,9 @@
|
||||
Class('A', 'code_test.h')
|
||||
header_code('#include <string>\n')
|
||||
global_declaration_code('''
|
||||
int get(A& a) { return a.x; }
|
||||
|
||||
std::string foo() { return "Hello!"; }
|
||||
''')
|
||||
module_code(' def("get", &get);\n')
|
||||
module_code(' def("foo", &foo);\n')
|
||||
14
pyste/tests/code_testUT.py
Normal file
14
pyste/tests/code_testUT.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import unittest
|
||||
from _code_test import *
|
||||
|
||||
class CodeTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A()
|
||||
a.x = 12
|
||||
self.assertEqual(get(a), 12)
|
||||
self.assertEqual(foo(), "Hello!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
3
pyste/tests/inherit.cpp
Normal file
3
pyste/tests/inherit.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "inherit.h"
|
||||
|
||||
int inherit::C::s = 1;
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
namespace inherit {
|
||||
|
||||
template<typename T>
|
||||
class A
|
||||
{
|
||||
@@ -16,3 +19,21 @@ class B : public A<int>
|
||||
public:
|
||||
int go() { return get(); }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
{
|
||||
enum ab { a = 1, b = 2 };
|
||||
int f1() { return 1; }
|
||||
int x;
|
||||
static int s;
|
||||
};
|
||||
|
||||
struct D : C
|
||||
{
|
||||
int f2() { return 2; }
|
||||
int y;
|
||||
};
|
||||
|
||||
struct X {};
|
||||
struct E: X, D {};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Doesn't work:
|
||||
A = Template('A', 'inherit.h')
|
||||
A_int = A('int')
|
||||
A = Template('inherit::A', 'inherit.h')
|
||||
A_int = A('int', 'A_int')
|
||||
|
||||
Class('B', 'inherit.h')
|
||||
|
||||
# Does work:
|
||||
#AllFromHeader('inherit.h')
|
||||
Class('inherit::B', 'inherit.h')
|
||||
Class('inherit::D', 'inherit.h')
|
||||
E = Class('inherit::E', 'inherit.h')
|
||||
exclude(E.s)
|
||||
exclude(E.ab)
|
||||
|
||||
30
pyste/tests/inherit2.h
Normal file
30
pyste/tests/inherit2.h
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace inherit2 {
|
||||
|
||||
struct A
|
||||
{
|
||||
int x;
|
||||
int getx() { return x; }
|
||||
int foo() { return 0; }
|
||||
int foo(int x) { return x; }
|
||||
};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
int y;
|
||||
int gety() { return y; }
|
||||
int foo() { return 1; }
|
||||
};
|
||||
|
||||
struct C : B
|
||||
{
|
||||
int z;
|
||||
int getz() { return z; }
|
||||
};
|
||||
|
||||
struct D : C
|
||||
{
|
||||
int w;
|
||||
int getw() { return w; }
|
||||
};
|
||||
|
||||
}
|
||||
2
pyste/tests/inherit2.pyste
Normal file
2
pyste/tests/inherit2.pyste
Normal file
@@ -0,0 +1,2 @@
|
||||
Class('inherit2::B', 'inherit2.h')
|
||||
Class('inherit2::D', 'inherit2.h')
|
||||
27
pyste/tests/inherit2UT.py
Normal file
27
pyste/tests/inherit2UT.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import unittest
|
||||
from _inherit2 import *
|
||||
|
||||
class InheritExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
b = B()
|
||||
d = D()
|
||||
|
||||
self.assert_(issubclass(D, B))
|
||||
b.x, b.y = 10, 5
|
||||
self.assertEqual(b.getx(), 10)
|
||||
self.assertEqual(b.gety(), 5)
|
||||
d.x, d.y, d.z, d.w = 20, 15, 10, 5
|
||||
self.assertEqual(d.getx(), 20)
|
||||
self.assertEqual(d.gety(), 15)
|
||||
self.assertEqual(d.getz(), 10)
|
||||
self.assertEqual(d.getw(), 5)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(b.foo(3), 3)
|
||||
|
||||
def wrong():
|
||||
return b.getw()
|
||||
self.assertRaises(AttributeError, wrong)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
39
pyste/tests/inherit3.h
Normal file
39
pyste/tests/inherit3.h
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
namespace inherit3 {
|
||||
|
||||
struct A
|
||||
{
|
||||
struct X { int y; };
|
||||
int x;
|
||||
virtual int foo() { return 0; }
|
||||
virtual int foo(int x) { return x; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
struct X { int y; };
|
||||
int x;
|
||||
int foo() { return 1; }
|
||||
A operator+(A o) const
|
||||
{
|
||||
A r;
|
||||
r.x = o.x + x;
|
||||
return r;
|
||||
}
|
||||
enum E { i, j };
|
||||
|
||||
};
|
||||
|
||||
struct C: A
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
2
pyste/tests/inherit3.pyste
Normal file
2
pyste/tests/inherit3.pyste
Normal file
@@ -0,0 +1,2 @@
|
||||
Class('inherit3::B', 'inherit3.h')
|
||||
Class('inherit3::C', 'inherit3.h')
|
||||
23
pyste/tests/inherit3UT.py
Normal file
23
pyste/tests/inherit3UT.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import unittest
|
||||
from _inherit3 import *
|
||||
|
||||
class testInherit3(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
def testInst(c):
|
||||
self.assertEqual(c.x, 0)
|
||||
self.assertEqual(c.foo(3), 3)
|
||||
x = c.X()
|
||||
self.assertEqual(x.y, 0)
|
||||
self.assertEqual(c.E.i, 0)
|
||||
self.assertEqual(c.E.j, 1)
|
||||
b = B()
|
||||
c = C()
|
||||
testInst(b)
|
||||
testInst(c)
|
||||
self.assertEqual(b.foo(), 1)
|
||||
self.assertEqual(c.foo(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -14,6 +14,15 @@ class InheritExampleTest(unittest.TestCase):
|
||||
self.assertEqual(b.go(), 1)
|
||||
self.assertEqual(b.get(), 1)
|
||||
|
||||
d = D()
|
||||
self.assert_(issubclass(D, B))
|
||||
self.assertEqual(d.x, 0)
|
||||
self.assertEqual(d.y, 0)
|
||||
self.assertEqual(d.s, 1)
|
||||
self.assertEqual(D.s, 1)
|
||||
self.assertEqual(d.f1(), 1)
|
||||
self.assertEqual(d.f2(), 2)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -17,6 +17,11 @@ inline C* new_C()
|
||||
return new C(10);
|
||||
}
|
||||
|
||||
inline C* new_C_zero()
|
||||
{
|
||||
return new C(0);
|
||||
}
|
||||
|
||||
inline int get(C* c)
|
||||
{
|
||||
return c->value;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
foo = Function('opaque::new_C', 'opaque.h')
|
||||
set_policy(foo, return_value_policy(return_opaque_pointer))
|
||||
foo = Function('opaque::new_C_zero', 'opaque.h')
|
||||
set_policy(foo, return_value_policy(return_opaque_pointer))
|
||||
Function('opaque::get', 'opaque.h' )
|
||||
A = Class('opaque::A', 'opaque.h')
|
||||
set_policy(A.new_handle, return_value_policy(return_opaque_pointer))
|
||||
|
||||
@@ -7,6 +7,8 @@ class OpaqueTest(unittest.TestCase):
|
||||
|
||||
c = new_C()
|
||||
self.assertEqual(get(c), 10)
|
||||
c = new_C_zero()
|
||||
self.assertEqual(get(c), 0)
|
||||
a = A()
|
||||
d = a.new_handle()
|
||||
self.assertEqual(a.get(d), 3.0)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#define OPERATORS_H
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace operators {
|
||||
|
||||
struct C
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
sys.path.append('../src/Pyste')
|
||||
import unittest
|
||||
import os.path
|
||||
from glob import glob
|
||||
|
||||
@@ -5,123 +5,65 @@ import glob
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
# 3 functions are needed for each plataform:
|
||||
# build_pyste(multiple, module)
|
||||
# compile_single(module)
|
||||
# compile_multiple(module)
|
||||
#
|
||||
#=============================================================================
|
||||
# win32 configuration
|
||||
#=============================================================================
|
||||
if sys.platform == 'win32':
|
||||
|
||||
includes = '-ID:/programming/libraries/boost-cvs/boost -IC:/Python/include'
|
||||
lib_dirs = '/libpath:D:/programming/libraries/boost-cvs/lib /libpath:C:/Python/libs'
|
||||
libs = 'boost_python.lib python22.lib'
|
||||
includes = '-ID:/programming/libraries/boost-cvs/boost -ID:/Bin/Python/include'
|
||||
build_pyste_cmd = 'python ../src/Pyste/pyste.py --cache-dir=cache %s ' % includes
|
||||
compile_single_cmd = 'icl /nologo /GR /GX -c %s -I. ' % includes
|
||||
link_single_cmd = 'link /nologo /DLL '\
|
||||
'/libpath:D:/programming/libraries/boost-cvs/lib /libpath:D:/Bin/Python/libs '\
|
||||
'boost_python.lib python23.lib /out:_%s.dll '
|
||||
obj_ext = 'obj'
|
||||
|
||||
def build_pyste(multiple, module):
|
||||
cmd = 'python ../src/pyste.py %s %s --module=%s %s.pyste'
|
||||
execute(cmd % (multiple, includes, '_' + module, module))
|
||||
|
||||
|
||||
def compile_single(module):
|
||||
start_building(module)
|
||||
cmd = 'icl /nologo /GR /GX -c %s -I.' % includes
|
||||
cmd += ' %s'
|
||||
module_obj = ''
|
||||
if os.path.isfile(module+'.cpp'):
|
||||
execute(cmd % (module+'.cpp'))
|
||||
module_obj = module + '.obj'
|
||||
execute(cmd % '_%s.cpp' % module)
|
||||
execute('link /nologo /DLL /out:_%s.dll %s %s %s %s' % \
|
||||
(module, lib_dirs, '_%s.obj' % module, module_obj, libs))
|
||||
end_building(module)
|
||||
|
||||
|
||||
def compile_multiple(module):
|
||||
start_building(module)
|
||||
cmd = 'icl /nologo /GR /GX -c %s -I.' % includes
|
||||
cmd += ' %s'
|
||||
module_obj = ''
|
||||
if os.path.isfile(module+'.cpp'):
|
||||
execute(cmd % (module+'.cpp'))
|
||||
module_obj = module + '.obj'
|
||||
files = glob.glob('_%s/*.cpp' % module)
|
||||
for f in files:
|
||||
execute(cmd % f)
|
||||
objs = [os.path.split(os.path.splitext(x)[0])[1] + '.obj' for x in files]
|
||||
objs.append(module_obj)
|
||||
execute('link /nologo /DLL /out:_%s.dll %s %s %s' % \
|
||||
(module, lib_dirs, ' '.join(objs), libs))
|
||||
end_building(module)
|
||||
|
||||
|
||||
def start_building(module):
|
||||
#print 'Building module %s...' % module,
|
||||
pass
|
||||
|
||||
|
||||
def end_building(module):
|
||||
pass
|
||||
#if os.path.isfile('_%s.dll' % module):
|
||||
# print ' done.'
|
||||
#else:
|
||||
# print 'FAILED!'
|
||||
#print
|
||||
|
||||
|
||||
elif sys.platform == 'posix':
|
||||
#=============================================================================
|
||||
# linux configuration
|
||||
#=============================================================================
|
||||
elif sys.platform == 'linux2':
|
||||
|
||||
def build_pyste(multiple, module):
|
||||
cmd = 'python ../src/pyste.py %s --module=%s %s.pyste'
|
||||
execute(cmd % (multiple, module))
|
||||
|
||||
build_pyste_cmd = 'python ../src/Pyste/pyste.py -I. '
|
||||
compile_single_cmd = 'g++ -shared -c -I. -I/usr/include/python2.2 '
|
||||
link_single_cmd = 'g++ -shared -o _%s.so -lboost_python '
|
||||
obj_ext = 'o'
|
||||
|
||||
|
||||
|
||||
def build_pyste(multiple, module):
|
||||
rest = '%s --module=_%s %s.pyste' % (multiple, module, module)
|
||||
execute(build_pyste_cmd + rest)
|
||||
|
||||
|
||||
def compile_single(module):
|
||||
module_obj = ''
|
||||
if os.path.isfile(module+'.cpp'):
|
||||
execute(compile_single_cmd + module+'.cpp')
|
||||
module_obj = module + '.' + obj_ext
|
||||
execute(compile_single_cmd + ('_%s.cpp' % module))
|
||||
link = link_single_cmd % module
|
||||
execute(link + ('_%s.%s ' % (module, obj_ext)) + module_obj)
|
||||
|
||||
|
||||
def compile_multiple(module):
|
||||
module_obj = ''
|
||||
if os.path.isfile(module+'.cpp'):
|
||||
execute(compile_single_cmd + module+'.cpp')
|
||||
module_obj = module + '.' + obj_ext
|
||||
files = glob.glob('_%s/*.cpp' % module)
|
||||
for f in files:
|
||||
execute(compile_single_cmd + f)
|
||||
def basename(name):
|
||||
return os.path.basename(os.path.splitext(name)[0])
|
||||
objs = [basename(x) + '.' + obj_ext for x in files]
|
||||
objs.append(module_obj)
|
||||
execute((link_single_cmd % module) + ' '.join(objs))
|
||||
|
||||
|
||||
def execute(cmd):
|
||||
#output = os.popen(cmd).read()
|
||||
#f = file('build.log', 'a')
|
||||
#f.write(output)
|
||||
#f.close()
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
|
||||
|
||||
def compile_pyste_files(multiple):
|
||||
pass
|
||||
#if not multiple:
|
||||
# ## compile each cpp into a shared library
|
||||
# #for cpp in glob.glob('*.cpp'):
|
||||
# # print
|
||||
# # print 'compiling', cpp
|
||||
# # out = os.path.splitext(cpp)[0] + '.so'
|
||||
# # cmdline = 'g++ -shared -o %s -I../example ' \
|
||||
# # '-I/usr/include/python2.2 -lboost_python %s' % (out, cpp)
|
||||
# # os.system(cmdline)
|
||||
#
|
||||
#else:
|
||||
# modules = get_modules()
|
||||
# # list cpp files in each module directory
|
||||
# print
|
||||
# for module in modules:
|
||||
# # compile each
|
||||
# for file in glob.glob(module+'/*.cpp'):
|
||||
# print 'compiling', file
|
||||
# out = os.path.splitext(file)[0] + '.obj'
|
||||
# cmdline = 'g++ -shared -c -o %s -I../example ' \
|
||||
# '-I/usr/include/python2.2 %s' % (out, file)
|
||||
# os.system(cmdline)
|
||||
# # generate a dynamic library
|
||||
# print 'linking'
|
||||
# objs = ' '.join([x for x in glob.glob(module+'/*.obj')])
|
||||
# out = module + '.so'
|
||||
# cmdline = 'g++ -shared -o %s -lboost_python %s' % (out, objs)
|
||||
# os.system(cmdline)
|
||||
|
||||
|
||||
def compile_file_posix(filename, outfilename):
|
||||
cmdline = 'g++ -shared -o %s -I../example ' \
|
||||
'-I/usr/include/python2.2 -lboost_python %s' % (outfilename, filename)
|
||||
execute(cmdline)
|
||||
|
||||
|
||||
|
||||
def run_tests():
|
||||
if os.system('python runtests.py') != 0:
|
||||
raise RuntimeError, 'tests failed'
|
||||
@@ -129,7 +71,7 @@ def run_tests():
|
||||
|
||||
def cleanup():
|
||||
modules = get_modules()
|
||||
extensions = '*.dll *.pyc *.obj *.exp *.lib'
|
||||
extensions = '*.dll *.pyc *.obj *.exp *.lib *.o *.so'
|
||||
files = []
|
||||
for module in modules:
|
||||
files.append('_' + module + '.cpp')
|
||||
@@ -162,7 +104,7 @@ def main(multiple, module=None):
|
||||
os.system('python %sUT.py' % modules[0])
|
||||
else:
|
||||
run_tests()
|
||||
cleanup()
|
||||
#cleanup()
|
||||
|
||||
|
||||
def get_modules():
|
||||
@@ -176,7 +118,7 @@ if __name__ == '__main__':
|
||||
else:
|
||||
module = None
|
||||
try:
|
||||
main('--multiple', module)
|
||||
# main('--multiple', module)
|
||||
main('', module)
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace unions {
|
||||
|
||||
class UnionTest
|
||||
{
|
||||
public:
|
||||
union // unions are not supported for now
|
||||
{
|
||||
int i;
|
||||
short s1;
|
||||
short s2;
|
||||
} mBad;
|
||||
|
||||
int mGood;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
UnionTest = Class('unions::UnionTest', 'unions.h')
|
||||
exclude(UnionTest.mBad)
|
||||
7
pyste/tests/vars.cpp
Normal file
7
pyste/tests/vars.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "vars.h"
|
||||
|
||||
const Color black = Color(0, 0, 0);
|
||||
const Color red = Color(255, 0, 0);
|
||||
const Color green = Color(0, 255, 0);
|
||||
const Color blue = Color(0, 0, 255);
|
||||
Color in_use = black;
|
||||
@@ -12,8 +12,8 @@ struct Color
|
||||
int b;
|
||||
};
|
||||
|
||||
const Color black = Color(0, 0, 0);
|
||||
const Color red = Color(255, 0, 0);
|
||||
const Color green = Color(0, 255, 0);
|
||||
const Color blue = Color(0, 0, 255);
|
||||
Color in_use = black;
|
||||
extern const Color black;
|
||||
extern const Color red;
|
||||
extern const Color green;
|
||||
extern const Color blue;
|
||||
extern Color in_use;
|
||||
|
||||
@@ -14,4 +14,5 @@ class VarsTest(unittest.TestCase):
|
||||
testColor(_vars.green, 0, 255, 0)
|
||||
testColor(_vars.blue, 0, 0, 255)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
{
|
||||
return name();
|
||||
}
|
||||
virtual int dummy() { return 0; }
|
||||
|
||||
protected:
|
||||
virtual int f_abs() = 0;
|
||||
@@ -23,6 +24,13 @@ private:
|
||||
virtual const char* name() { return "C"; }
|
||||
};
|
||||
|
||||
struct D
|
||||
{
|
||||
virtual int dummy() { return 0; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c) { return c.f(); }
|
||||
inline int call_dummy(C* c) { return c->dummy(); }
|
||||
inline int call_dummy(D* d) { return d->dummy(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
Class('virtual_::C', 'virtual.h')
|
||||
C = Class('virtual_::C', 'virtual.h')
|
||||
final(C.dummy)
|
||||
D = Class('virtual_::D', 'virtual.h')
|
||||
final(D.dummy)
|
||||
Function('virtual_::call_f', 'virtual.h')
|
||||
Function('virtual_::call_dummy', 'virtual.h')
|
||||
|
||||
@@ -5,12 +5,14 @@ struct A
|
||||
{
|
||||
virtual int f() { return 0; }
|
||||
virtual int f1() { return 10; }
|
||||
virtual A* make_new() { return new A; }
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
virtual int f() { return 1; }
|
||||
virtual int f2() { return 20; }
|
||||
virtual A* make_new() { return new B; }
|
||||
};
|
||||
|
||||
inline int call_fs(A*a)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Class('virtual2::A', 'virtual2.h')
|
||||
Class('virtual2::B', 'virtual2.h')
|
||||
A = Class('virtual2::A', 'virtual2.h')
|
||||
set_policy(A.make_new, return_value_policy(manage_new_object))
|
||||
B = Class('virtual2::B', 'virtual2.h')
|
||||
set_policy(B.make_new, return_value_policy(manage_new_object))
|
||||
Function('virtual2::call_fs', 'virtual2.h')
|
||||
Function('virtual2::call_f', 'virtual2.h')
|
||||
|
||||
@@ -12,7 +12,14 @@ class Virtual2Test(unittest.TestCase):
|
||||
self.assertEqual(call_fs(b), 30)
|
||||
self.assertEqual(call_f(a), 0)
|
||||
self.assertEqual(call_f(b), 1)
|
||||
|
||||
nb = b.make_new()
|
||||
na = a.make_new()
|
||||
self.assertEqual(na.f1(), 10)
|
||||
self.assertEqual(nb.f1(), 10)
|
||||
self.assertEqual(nb.f2(), 20)
|
||||
self.assertEqual(call_fs(nb), 30)
|
||||
self.assertEqual(call_f(na), 0)
|
||||
self.assertEqual(call_f(nb), 1)
|
||||
class C(B):
|
||||
def f1(self): return 1
|
||||
def f2(self): return 2
|
||||
|
||||
@@ -5,33 +5,45 @@ class VirtualTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
|
||||
class D(C):
|
||||
class E(C):
|
||||
def f_abs(self):
|
||||
return 3
|
||||
def dummy(self):
|
||||
# override should not work
|
||||
return 100
|
||||
|
||||
class E(C):
|
||||
class F(C):
|
||||
def f(self):
|
||||
return 10
|
||||
def name(self):
|
||||
return 'E'
|
||||
return 'F'
|
||||
|
||||
class G(D):
|
||||
def dummy(self):
|
||||
# override should not work
|
||||
return 100
|
||||
|
||||
d = D()
|
||||
e = E()
|
||||
f = F()
|
||||
|
||||
self.assertEqual(d.f(), 3)
|
||||
self.assertEqual(call_f(d), 3)
|
||||
self.assertEqual(e.f(), 10)
|
||||
self.assertEqual(call_f(e), 10)
|
||||
self.assertEqual(d.get_name(), 'C')
|
||||
self.assertEqual(e.f(), 3)
|
||||
self.assertEqual(call_f(e), 3)
|
||||
self.assertEqual(f.f(), 10)
|
||||
self.assertEqual(call_f(f), 10)
|
||||
self.assertEqual(e.get_name(), 'C')
|
||||
#self.assertEqual(e.get_name(), 'E') check this later
|
||||
|
||||
c = C()
|
||||
def bar(arg):
|
||||
c.bar(arg)
|
||||
bar(1) # ok
|
||||
bar('a') # ok
|
||||
self.assertRaises(TypeError, bar, 1.0)
|
||||
|
||||
c.bar(1) # ok
|
||||
c.bar('a') # ok
|
||||
self.assertRaises(TypeError, c.bar, 1.0)
|
||||
|
||||
# test no_overrides
|
||||
d = G()
|
||||
self.assertEqual(e.dummy(), 100)
|
||||
self.assertEqual(call_dummy(e), 0)
|
||||
self.assertEqual(d.dummy(), 100)
|
||||
self.assertEqual(call_dummy(d), 0)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user