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

Compare commits

..

119 Commits

Author SHA1 Message Date
nobody
c1a1e3be8a This commit was manufactured by cvs2svn to create tag
'version_0-9-15'.

[SVN r19665]
2003-08-17 19:35:01 +00:00
Bruno da Silva de Oliveira
929badf4c6 Added support for insertion of user code in the generated code
[SVN r19664]
2003-08-17 19:35:00 +00:00
Bruno da Silva de Oliveira
c4a3f2c04f no message
[SVN r19652]
2003-08-16 21:11:50 +00:00
Bruno da Silva de Oliveira
a933e458b3 - Fixed a bug in the pure virtual functions
[SVN r19648]
2003-08-16 19:13:45 +00:00
Bruno da Silva de Oliveira
06b8320815 - Added exception specifiers (patch by Gottfried).
[SVN r19645]
2003-08-16 18:21:44 +00:00
Dave Abrahams
7f3aceafd2 Fix public/private error.
[SVN r19636]
2003-08-16 13:56:52 +00:00
Dave Abrahams
da5979931c class.hpp, object/select_holder.hpp, object/pointer_holder.hpp -
fix a problem which was causing value_holder<T> to be instantiated
   on abstract classes.  Now we compute the held_type at an outer
   level thereby avoiding the inner instantiation.

object_core.hpp -

   workarounds for GCC 2.x bugs

suite/indexing/detail/indexing_suite_detail.hpp -

   workaround for a CWPro8 bug


[SVN r19635]
2003-08-16 13:48:34 +00:00
Dave Abrahams
d8c7e75095 Fix the fix... again!
[SVN r19617]
2003-08-15 03:45:34 +00:00
Joel de Guzman
187506c97f added map value type (std::pair) wrapper to map_indexing_suite.hpp
[SVN r19616]
2003-08-15 03:03:27 +00:00
Joel de Guzman
145c6d1e4f moved map value type (std::pair) wrapper to map_indexing_suite.hpp
[SVN r19615]
2003-08-15 03:01:32 +00:00
Dave Abrahams
e2973f27f9 Fix the fix ;-)
[SVN r19613]
2003-08-14 22:53:30 +00:00
Dave Abrahams
976b8180ae Workaround a VC7 bug with nested enums
[SVN r19611]
2003-08-14 22:48:01 +00:00
Joel de Guzman
37acf41d43 Added map_indexing_suite test
[SVN r19600]
2003-08-14 15:05:02 +00:00
Joel de Guzman
6f26778491 Initial commit map_indexing_suite tests
[SVN r19599]
2003-08-14 15:04:25 +00:00
Joel de Guzman
834d815c87 mapping suite update
[SVN r19598]
2003-08-14 15:03:14 +00:00
Joel de Guzman
57e58c445b Tweaks to accomodate map_indexing_suite
[SVN r19588]
2003-08-14 12:14:25 +00:00
Joel de Guzman
8a1a8342d6 Initial commit map_indexing_suite
[SVN r19587]
2003-08-14 12:13:15 +00:00
Joel de Guzman
fa70ddc2c5 Preparing for std::map suite
[SVN r19566]
2003-08-12 21:21:47 +00:00
Joel de Guzman
8ca32bb494 Minor tweak in preparation for map_indexing_suite.hpp
[SVN r19565]
2003-08-12 18:36:55 +00:00
Joel de Guzman
f6c82eba0c changed def_arg to def_visitor
[SVN r19564]
2003-08-12 18:35:00 +00:00
Joel de Guzman
344044a315 updated the include path to vector_indexing_suite.hpp
[SVN r19563]
2003-08-12 18:13:19 +00:00
Joel de Guzman
b10805dc4c moved to new "suite" directory
[SVN r19562]
2003-08-12 18:09:21 +00:00
Joel de Guzman
07f397e2ed Moved to new "suite" directory
[SVN r19561]
2003-08-12 18:07:11 +00:00
Dave Abrahams
054dc439d2 Workaround msvc bug
[SVN r19553]
2003-08-12 14:17:52 +00:00
Dave Abrahams
5008dcbdd4 Make sure the class object and cast relationships are registered for
virtual function dispatch classes.


[SVN r19543]
2003-08-12 04:36:42 +00:00
Dave Abrahams
9c6650963f Use def_visitor to simplify class def(...) handling.
Workarounds for intel6 and vc6.


[SVN r19533]
2003-08-11 14:56:30 +00:00
Dave Abrahams
d482d57689 added properties tests
[SVN r19532]
2003-08-11 14:30:04 +00:00
Dave Abrahams
edf6516085 Python 2.3 compatibility.
[SVN r19530]
2003-08-11 11:07:28 +00:00
Dave Abrahams
957ac66e14 Added missing #include
Use BOOST_EXPLICIT_TEMPLATE_TYPE


[SVN r19529]
2003-08-11 02:21:34 +00:00
Dave Abrahams
07ce84c4e7 Repair bugs introduced during previous workaround
[SVN r19526]
2003-08-11 02:01:15 +00:00
Bruno da Silva de Oliveira
918636ff03 - Fixed a bug where in some classes the virtual methods were being definied incorrectly
[SVN r19525]
2003-08-10 23:21:25 +00:00
Dave Abrahams
83a6adbfa9 Added properties news item
changed the name of the static property class to
Boost.Python.StaticProperty (was Boost.Python.Class).


[SVN r19521]
2003-08-10 22:56:58 +00:00
Dave Abrahams
fcbc1d562f Added properties unit test from Roman Yakovenko
<romany-at-actimize.com>.


[SVN r19520]
2003-08-10 22:51:51 +00:00
Dave Abrahams
c3b4b58075 Extended CWPro8 overload ambiguity workaround to cover make_setter as
well as make_getter.


[SVN r19519]
2003-08-10 22:50:38 +00:00
Bruno da Silva de Oliveira
568b62a8a4 - Little bug where the memory cache was not being used
[SVN r19517]
2003-08-10 21:51:28 +00:00
Bruno da Silva de Oliveira
da34e7f507 - Abstract methods fix
- converts \ to / on windows


[SVN r19516]
2003-08-10 21:47:50 +00:00
Joel de Guzman
a0c31b47e5 refactored code + cleanup
[SVN r19508]
2003-08-10 15:20:10 +00:00
Joel de Guzman
5fb677c0c5 initial commit of container utils
[SVN r19507]
2003-08-10 15:19:23 +00:00
Bruno da Silva de Oliveira
168476382a - incremental code and some fixes
[SVN r19499]
2003-08-09 21:18:12 +00:00
Bruno da Silva de Oliveira
7fa6a29814 no message
[SVN r19498]
2003-08-09 20:57:04 +00:00
Bruno da Silva de Oliveira
f2b51da0ab - Fix a bug where a declaration was appearing more than once in an intermediate class in an hierarchy not fully-exported
[SVN r19489]
2003-08-08 02:56:04 +00:00
Joel de Guzman
53726746b8 Clean-up, refactored and added NoSlice option.
[SVN r19488]
2003-08-07 17:16:07 +00:00
Joel de Guzman
fe0b59f559 some trivial fixes.
[SVN r19485]
2003-08-07 12:29:54 +00:00
Joel de Guzman
c014dee6dc Fixed no proxy handling for containers of primitive types.
[SVN r19484]
2003-08-07 08:45:57 +00:00
Joel de Guzman
90c69d961e Added named visitor .def facility.
[SVN r19483]
2003-08-07 03:07:20 +00:00
Dave Abrahams
342f7db678 Workaround vc7.1 typeid problem with cv-qualified arrays.
[SVN r19474]
2003-08-06 13:51:03 +00:00
Joel de Guzman
9eb704f85a fixed iteration scheme and added append and extend methods
[SVN r19469]
2003-08-06 08:06:09 +00:00
Dave Abrahams
7754a91929 Update docs for static data support.
[SVN r19462]
2003-08-05 13:41:21 +00:00
Dave Abrahams
e4dc639e54 Allow mutating operations on self for all operators
[SVN r19454]
2003-08-05 03:15:37 +00:00
Ralf W. Grosse-Kunstleve
5d90101671 workaround for MIPSpro, thanks to John Spicer
[SVN r19453]
2003-08-05 03:03:49 +00:00
Ralf W. Grosse-Kunstleve
437fb70852 Tru64 cxx requires X::operator!=
[SVN r19450]
2003-08-05 00:49:33 +00:00
Dave Abrahams
d598404c48 initial commit
[SVN r19449]
2003-08-04 23:52:01 +00:00
Joel de Guzman
32c7088600 added missing typename and include file
[SVN r19448]
2003-08-04 23:34:52 +00:00
Joel de Guzman
ccede29816 added missing line feed at end of source
[SVN r19447]
2003-08-04 23:34:02 +00:00
Ralf W. Grosse-Kunstleve
b55b7e2f7b workaround for Mac OS 10 gcc 3.3 static initialization bug
[SVN r19446]
2003-08-04 22:09:16 +00:00
Ralf W. Grosse-Kunstleve
9217a6a253 avoid (incorrect) Tru64 cxx 6.5.1 warning
[SVN r19445]
2003-08-04 20:54:07 +00:00
Dave Abrahams
07c1319b99 Added the new arg class from
"nickm-at-sitius.com" (Nikolay Mladenov) which supplies the
ability to wrap functions that can be called with ommitted
arguments in the middle.


[SVN r19441]
2003-08-04 17:46:48 +00:00
Dave Abrahams
714b5dc26e missing checkin
[SVN r19439]
2003-08-04 17:36:49 +00:00
Joel de Guzman
1f715958f9 Fixed get_slice
[SVN r19421]
2003-08-04 05:09:23 +00:00
Joel de Guzman
0922aca873 Better usage of handle<>.
[SVN r19420]
2003-08-04 03:24:41 +00:00
Joel de Guzman
30ec6181b5 Fixed negative ref count bug
[SVN r19419]
2003-08-04 02:36:47 +00:00
Dave Abrahams
b28d586612 Move assignment operator inline as a workaround for a vc7 bug.
[SVN r19416]
2003-08-03 14:19:09 +00:00
Dave Abrahams
f48aacf477 added internals
[SVN r19390]
2003-07-31 18:03:17 +00:00
Dave Abrahams
bfa868a440 Workarounds for VC6 bugs
[SVN r19389]
2003-07-31 15:56:10 +00:00
Dave Abrahams
f01ff3a277 Prune #includes
[SVN r19382]
2003-07-31 01:04:51 +00:00
Dave Abrahams
d88e6bf688 object_core.hpp - use detail/is_xxx to generate template identifiers
object_operators.hpp - use SFINAE to prevent ADL from finding
        generalized operators inappropriately


[SVN r19377]
2003-07-30 23:48:06 +00:00
Dave Abrahams
a3cdacd088 Bug fix -- we weren't handling NULL keywords dictionaries in raw_function
[SVN r19359]
2003-07-30 11:34:50 +00:00
Joel de Guzman
81d99c855f Minor tweaks
[SVN r19335]
2003-07-29 04:47:34 +00:00
Joel de Guzman
5cd110f625 Comments from Dave + Editing + Proof reading and stuff
[SVN r19334]
2003-07-29 04:30:37 +00:00
Joel de Guzman
416895ff30 linked in the indexing suite documentation
[SVN r19315]
2003-07-26 05:49:57 +00:00
Joel de Guzman
e41abb6e92 Initial commit of indexing suite documentation
[SVN r19314]
2003-07-26 05:48:59 +00:00
Joel de Guzman
a6440a3fa6 Minor tweaks
[SVN r19313]
2003-07-26 05:47:11 +00:00
Joel de Guzman
2dece7ecaf added __iter__ and __contains__
[SVN r19311]
2003-07-26 01:50:35 +00:00
Dave Abrahams
7aae525587 Added RationalDiscovery
[SVN r19300]
2003-07-24 16:38:23 +00:00
Ralf W. Grosse-Kunstleve
ac5314093b fixing some trivial bugs (missing or misplaced typename); work around gcc 3.2 bug
[SVN r19299]
2003-07-24 15:07:05 +00:00
Ralf W. Grosse-Kunstleve
1524fb9fa9 flotsam removed
[SVN r19297]
2003-07-24 13:51:06 +00:00
Joel de Guzman
957549460b Initial Commit of Indexing Suite
[SVN r19296]
2003-07-24 12:02:57 +00:00
Joel de Guzman
3b33f54fb8 Added generic visitation mechanism.
[SVN r19288]
2003-07-24 01:44:18 +00:00
Ralf W. Grosse-Kunstleve
42ab6b6b66 unused variable removed (to avoid MIPSpro warning)
[SVN r19287]
2003-07-23 19:00:55 +00:00
Dave Abrahams
f59a5bbabc Stop printing return types in error messages.
[SVN r19286]
2003-07-23 17:04:05 +00:00
Dave Abrahams
0be371d747 Added cross-module exception test
[SVN r19282]
2003-07-23 15:17:03 +00:00
Dave Abrahams
2b52210291 remove (again!) extra diagnostic info
[SVN r19281]
2003-07-23 14:14:00 +00:00
Dave Abrahams
96a7bce78e Give feedback about the name and namespace of functions in error messages.
[SVN r19280]
2003-07-23 13:08:59 +00:00
Dave Abrahams
c1e1ea697c Added Metafaq link
[SVN r19278]
2003-07-23 11:43:06 +00:00
Dave Abrahams
874d6ebf2c Kill off nasty diagnostic printing.
[SVN r19277]
2003-07-23 11:11:56 +00:00
Dave Abrahams
77f5eb703c Attempt to work around a GCC EH problem by sticking a virtual function
in error_already_set and defining it in the library.

Removed some flotsam


[SVN r19274]
2003-07-23 03:00:48 +00:00
Dave Abrahams
af53ae8329 Implemented better error reporting for argument match errors.
[SVN r19271]
2003-07-23 01:31:34 +00:00
Dave Abrahams
8f76b8880e Remove bad #includes
[SVN r19269]
2003-07-22 23:55:09 +00:00
Dave Abrahams
fa398734be initial commit
[SVN r19267]
2003-07-22 23:53:06 +00:00
Dave Abrahams
362d20a8c7 Fixed editing error
[SVN r19265]
2003-07-22 20:12:39 +00:00
Dave Abrahams
6a33b8aeeb Implemented better error reporting for argument match errors.
[SVN r19264]
2003-07-22 20:12:07 +00:00
Dave Abrahams
d4e06ac436 Preparation for delivering nicely-formatted error messages in
Boost.Python.  The major change is that, instead of being
boost::function2<PyObject*,PyObject*,PyObject*>, py_function is now a
runtime-polymorphic wrapper for compile-time polymorphic
behavior (just like function) of our own which carries more
information/behaviors.  In particular, you can retrieve an array of
c-strings describing the types in the function signature.
Additionally, the minimum and maximum arity are stored in the
py_function object instead of in the 'function' object which wraps it.

* data_members.hpp -

     Adjustments for the new py_function.  Workarounds for CodeWarrior
     Pro 8.3 bugs in function template argument deduction with
     pointers-to-members.

* has_back_reference.hpp, test/back_reference.cpp,
  test/select_holder.cpp -

     Updated to follow the metafunction protocol

* init.hpp, detail/defaults_gen.hpp -

     Make Keywords a more-specific type in function signatures to
     prevent string literals that show up as char[N] from binding to
     the wrong argument (at least Intel 7.1 for Windows does this).

* make_function.hpp -

     Adjustments for the new py_function.  Arities are now computed
     by caller<>.

* opaque_pointer_converter.hpp, type_id.hpp -

     Use BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS facilities;
     generate specializations that all compilers can handle.

* raw_function.hpp -

     Adjustments for the new py_function.

* caller.hpp -

     Added arity and signature type name reporting.

* detail/config.hpp

     Enable __declspec(dllexport) for Cygwin, thereby fixing the
     recent horrible Cygwin linking problems.


* detail/msvc_typeinfo.hpp -

     Always pass boost::type<T>* explicitly, thereby working around
     incompatible notions of how to specialize function templates with
     default arguments on various compilers.

*   object/function.hpp
  , object/function_handle.hpp
  , object/function_object.hpp
  , object/function_object.cpp

     Adjustments for the new py_function.  Arities are carried by
     py_function.

* object/iterator.hpp, object/iterator.cpp

     Adjustments for the new py_function; we have to compute a
     signature of types to construct it with.

* object/py_function.hpp

     Removed dependency on boost::function; see the comment at the
     top of this entry for more details.

* object/select_holder.hpp

     Clean up to more closely follow MPL idioms.

* test/Jamfile -

     Adjust the embedding test for the new Cygwin use of declspec.
     Update bases and pointee tests with missing properties.

* test/input_iterator.cpp -

     Updates for the new iterator adaptors.

* test/opaque.py -

     Add Python encoding comment to suppress PendinDeprecationWarning
     with recent Python builds.

* test/str.cpp

     Pass a Python long instead of a float to string.expandtabs,
     suppressing a PendinDeprecationWarning with recent Python builds.

* libs/utility/counting_iterator_example.cpp

     Borland workaround

* libs/utility/indirect_iterator_example.cpp

     const-correctness fix.

*


[SVN r19247]
2003-07-22 00:06:41 +00:00
Dave Abrahams
817dcd37e0 Get Cygwin linking again
User-readable type name printing for GCC


[SVN r19236]
2003-07-21 02:14:58 +00:00
Dave Abrahams
25bfd3c50f Suppress a GCC 2.x ICE
[SVN r19235]
2003-07-21 02:12:04 +00:00
Dave Abrahams
b13c902fb0 * added return_arg policy from Nikolay Mladenov
* removed duplication from reference.html

* improved automatic redirection messages


[SVN r19226]
2003-07-19 23:49:06 +00:00
Dave Abrahams
c95ef44b02 Added Kig
[SVN r19154]
2003-07-16 15:40:27 +00:00
Bruno da Silva de Oliveira
162727590c - moved register_ptr_to_python up one level.
[SVN r19123]
2003-07-15 01:05:07 +00:00
Vladimir Prus
7e159844fb Update for current Boost.Build V2.
[SVN r19037]
2003-07-11 06:04:35 +00:00
Dave Abrahams
787b79cc2c Added NeuraLab
[SVN r18979]
2003-07-08 13:10:59 +00:00
Bruno da Silva de Oliveira
b77652b499 - fixed staticmethod bug
- fixed hierarchies bug when using AllFromHeader


[SVN r18971]
2003-07-07 20:00:40 +00:00
Bruno da Silva de Oliveira
0c8444b8ed - fixed bug of --multiple
- new function: hold_with_shared_ptr
- SPECIALIZE_TYPE_ID bug


[SVN r18969]
2003-07-07 19:00:52 +00:00
Bruno da Silva de Oliveira
3e6ee799ba - --multiple now generates one cpp per pyste file.
[SVN r18945]
2003-07-06 01:16:27 +00:00
Bruno da Silva de Oliveira
dd14ccb115 - --multiple now generates one cpp per pyste file.
[SVN r18944]
2003-07-06 01:12:26 +00:00
Bruno da Silva de Oliveira
ba0fcd27c3 - Various bug fixes
- Changed the internal code to the way it was


[SVN r18941]
2003-07-04 22:47:27 +00:00
Bruno da Silva de Oliveira
d476e67067 - Fixed "char**" bug
- Lots of internal changes: phase 1 of Meta-Programming complete.


[SVN r18919]
2003-07-03 00:00:23 +00:00
Bruno da Silva de Oliveira
4588f5e9ab no message
[SVN r18884]
2003-06-29 17:47:45 +00:00
Bruno da Silva de Oliveira
68f54d364b - register_ptr_to_python addition
[SVN r18880]
2003-06-27 18:34:25 +00:00
Dave Abrahams
7dba18e7b9 Test that shared_ptr<Derived> can be converted to shared_ptr<Base>
[SVN r18851]
2003-06-20 22:57:37 +00:00
Dave Abrahams
67b265fe96 Remove duplicated sections
[SVN r18835]
2003-06-18 12:22:28 +00:00
Bruno da Silva de Oliveira
8289269a86 *** empty log message ***
[SVN r18828]
2003-06-18 00:05:01 +00:00
Bruno da Silva de Oliveira
9f711ed821 - Changed "no_override" to "final"
[SVN r18826]
2003-06-17 23:25:16 +00:00
Bruno da Silva de Oliveira
73e2ab5125 - Added a new test exercising the new automatic inheritation
[SVN r18815]
2003-06-17 01:56:45 +00:00
Bruno da Silva de Oliveira
7ea2ab1672 - 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).


[SVN r18814]
2003-06-17 01:34:26 +00:00
Bruno da Silva de Oliveira
c821e903f8 Added tests for linux.
[SVN r18809]
2003-06-16 20:36:36 +00:00
Ralf W. Grosse-Kunstleve
54db04521a MIPSpro workaround
[SVN r18744]
2003-06-09 13:10:34 +00:00
Bruno da Silva de Oliveira
91fdecd76f - Changed the filename of one of the doc files to limit it to 32 chars.
[SVN r18709]
2003-06-08 22:51:37 +00:00
Dave Abrahams
f140a74a13 Added MinGW tips
[SVN r18695]
2003-06-06 11:18:34 +00:00
Bruno da Silva de Oliveira
4854a2a81b - Added another entry, about ESSS.
[SVN r18685]
2003-06-06 00:04:51 +00:00
Bruno da Silva de Oliveira
d94bb65006 - Major improvements in memory usage.
[SVN r18681]
2003-06-05 15:14:52 +00:00
79 changed files with 2433 additions and 1543 deletions

View File

@@ -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
View 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

View File

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

View File

@@ -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>

View File

@@ -26,9 +26,9 @@
</table>
<p>
Even thought Pyste can identify various elements in the C++ code, like virtual
methods, attributes, and so on, one thing that it can't do is to guess the
semantics of functions that return pointers or references. In this case, the
user must manually specify the policy. Policies are explained in the
member functions, attributes, and so on, one thing that it can't do is to
guess the semantics of functions that return pointers or references. In this
case, the user must manually specify the policy. Policies are explained in the
<a href="../../doc/tutorial/doc/call_policies.html">
tutorial</a>.</p>
<p>
@@ -44,8 +44,8 @@ becomes in Pyste: </p>
<span class=identifier>return_internal_reference</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=identifier>with_custodian_and_ward</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>))
</span></pre></code>
<p>
The user can specify policies for functions and methods with the <tt>set_policy</tt>
function:</p>
The user can specify policies for functions and virtual member functions with
the <tt>set_policy</tt> function:</p>
<code><pre>
<span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>f</span><span class=special>, </span><span class=identifier>return_internal_reference</span><span class=special>())
</span><span class=identifier>set_policy</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>return_value_policy</span><span class=special>(</span><span class=identifier>manage_new_object</span><span class=special>))
@@ -54,10 +54,11 @@ function:</p>
<tr>
<td class="note_box">
<img src="theme/note.gif"></img> <b>What if a function or method needs a policy and the user
doesn't set one?</b><br><br> If a function/method needs a policy and one was not
set, Pyste will issue a error. The user should then go in the interface file
and set the policy for it, otherwise the generated cpp won't compile.
<img src="theme/note.gif"></img> <b>What if a function or member function needs a policy and
the user doesn't set one?</b><br><br> If a function needs a policy and one
was not set, Pyste will issue a error. The user should then go in the
interface file and set the policy for it, otherwise the generated cpp won't
compile.
</td>
</tr>
</table>
@@ -66,7 +67,7 @@ and set the policy for it, otherwise the generated cpp won't compile.
<td class="note_box">
<img src="theme/note.gif"></img>
Note that, for functions/methods that return <tt>const T&amp;</tt>, the policy
Note that, for functions that return <tt>const T&amp;</tt>, the policy
<tt>return_value_policy&lt;copy_const_reference&gt;()</tt> wil be used by default, because
that's normally what you want. You can change it to something else if you need
to, though.

View File

@@ -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')

View File

@@ -25,7 +25,7 @@
</tr>
</table>
<p>
You can easily rename functions, classes, methods, attributes, etc. Just use the
You can easily rename functions, classes, member functions, attributes, etc. Just use the
function <tt>rename</tt>, like this:</p>
<code><pre>
<span class=identifier>World </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
@@ -34,7 +34,7 @@ function <tt>rename</tt>, like this:</p>
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>show</span><span class=special>, </span><span class=string>&quot;Show&quot;</span><span class=special>)
</span></pre></code>
<p>
You can rename methods and attributes using this syntax:</p>
You can rename member functions and attributes using this syntax:</p>
<code><pre>
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>&quot;Greet&quot;</span><span class=special>)
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>&quot;Set&quot;</span><span class=special>)
@@ -43,7 +43,7 @@ You can rename methods and attributes using this syntax:</p>
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>blue</span><span class=special>, </span><span class=string>&quot;Blue&quot;</span><span class=special>)
</span></pre></code>
<p>
You can exclude functions, classes, methods, attributes, etc, in the same way,
You can exclude functions, classes, member functions, attributes, etc, in the same way,
with the function <tt>exclude</tt>:</p>
<code><pre>
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>)
@@ -59,6 +59,18 @@ To access the operators of a class, access the member <tt>operator</tt> like thi
</span></pre></code>
<p>
The string inside the brackets is the same as the name of the operator in C++.<br></p>
<a name="virtual_member_functions"></a><h2>Virtual Member Functions</h2><p>
Pyste automatically generates wrappers for virtual member functions, but you
may want to disable this behaviour (for performance reasons, or to let the
code more clean) if you do not plan to override the functions in Python. To do
this, use the function <tt>final</tt>:</p>
<code><pre>
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
</span><span class=identifier>final</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>foo</span><span class=special>) </span>##<span class=identifier>C</span><span class=special>::</span><span class=identifier>foo </span><span class=identifier>is </span><span class=identifier>a </span><span class=keyword>virtual </span><span class=identifier>member </span><span class=identifier>function
</span></pre></code>
<p>
No virtual wrapper code will be generated for the virtual member function
C::foo that way.</p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>

View File

@@ -55,8 +55,8 @@ Usage:
where options are:
-I &lt;path&gt; add an include path
-D &lt;symbol&gt; 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: &lt;module&gt;.cpp)
in --multiple mode, this will be a directory
--no-using do not declare &quot;using namespace boost&quot;;

View File

@@ -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>

View File

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

View File

@@ -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>

View File

@@ -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
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env python
from Pyste import pyste
pyste.main()

18
pyste/install/setup.py Normal file
View 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'},
)

View File

@@ -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

View File

@@ -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')

View File

@@ -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

View 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

View 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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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.'

View 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

View File

@@ -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!"

View 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')

View File

@@ -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()

View File

@@ -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)

View File

View 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)

View File

@@ -0,0 +1,5 @@
# a list of Exporter instances
exporters = []
current_interface = None # the current interface file being processed

View File

@@ -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

View File

@@ -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
View 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()

View File

@@ -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

View File

@@ -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)

View File

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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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')

View 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(); }
}

View File

@@ -0,0 +1,3 @@
Class('abstract::A', 'abstract_test.h')
Class('abstract::B', 'abstract_test.h')
Function('abstract::call', 'abstract_test.h')

View 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()

View File

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

View File

@@ -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
View File

@@ -0,0 +1,4 @@
struct A {
int x;
};

View 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')

View 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
View File

@@ -0,0 +1,3 @@
#include "inherit.h"
int inherit::C::s = 1;

View File

@@ -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 {};
}

View File

@@ -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
View 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; }
};
}

View File

@@ -0,0 +1,2 @@
Class('inherit2::B', 'inherit2.h')
Class('inherit2::D', 'inherit2.h')

27
pyste/tests/inherit2UT.py Normal file
View 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
View 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
{
};
}

View File

@@ -0,0 +1,2 @@
Class('inherit3::B', 'inherit3.h')
Class('inherit3::C', 'inherit3.h')

23
pyste/tests/inherit3UT.py Normal file
View 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()

View File

@@ -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__':

View File

@@ -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;

View File

@@ -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))

View File

@@ -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)

View File

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

View File

@@ -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

View File

@@ -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

View File

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

View File

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

7
pyste/tests/vars.cpp Normal file
View 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;

View File

@@ -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;

View File

@@ -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()

View File

@@ -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(); }
}

View File

@@ -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')

View File

@@ -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)

View File

@@ -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')

View File

@@ -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

View File

@@ -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)