mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
Compare commits
1 Commits
boost-1.30
...
boost-1.30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7f4093bd1 |
@@ -1,76 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Exporting All Declarations from a Header</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="wrappers.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="theme/c%2B%2Bboost.gif">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Exporting All Declarations from a Header</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Pyste also supports a mechanism to export all declarations found in a header
|
||||
file. Suppose again our file, <tt>hello.h</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>World
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {}
|
||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>show</span><span class=special>(</span><span class=identifier>choice </span><span class=identifier>c</span><span class=special>) { </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=string>"value: " </span><span class=special><< (</span><span class=keyword>int</span><span class=special>)</span><span class=identifier>c </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; }
|
||||
</span></pre></code>
|
||||
<p>
|
||||
You can just use the <tt>AllFromHeader</tt> construct:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>hello </span><span class=special>= </span><span class=identifier>AllFromHeader</span><span class=special>(</span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
this will export all the declarations found in <tt>hello.h</tt>, which is equivalent
|
||||
to write:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Class</span><span class=special>(</span><span class=string>"World"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Enum</span><span class=special>(</span><span class=string>"choice"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=string>"show"</span><span class=special>, </span><span class=string>"hello.h"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that you can still use the functions <tt>rename</tt>, <tt>set_policy</tt>, <tt>exclude</tt>, etc. Just access
|
||||
the members of the header object like this:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=string>"Greet"</span><span class=special>)
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>set</span><span class=special>, </span><span class=string>"Set"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
To use this examples, just execute the command-line:
|
||||
|
||||
pyste --module=<example> <example>.pyste
|
||||
|
||||
For more information, please refer to the documentation.
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace basic {
|
||||
|
||||
struct C
|
||||
{
|
||||
virtual int f(int x = 10)
|
||||
{
|
||||
return x*2;
|
||||
}
|
||||
|
||||
int foo(int x=1){
|
||||
return x+1;
|
||||
}
|
||||
};
|
||||
|
||||
int call_f(C& c)
|
||||
{
|
||||
return c.f();
|
||||
}
|
||||
|
||||
int call_f(C& c, int x)
|
||||
{
|
||||
return c.f(x);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
Class('basic::C', 'basic.h')
|
||||
Function('basic::call_f', 'basic.h')
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace enums {
|
||||
|
||||
enum color { red, blue };
|
||||
|
||||
struct X
|
||||
{
|
||||
enum choices
|
||||
{
|
||||
good = 1,
|
||||
bad = 2
|
||||
};
|
||||
|
||||
int set(choices c)
|
||||
{
|
||||
return (int)c;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
color = Enum('enums::color', 'enums.h')
|
||||
rename(color.red, 'Red')
|
||||
rename(color.blue, 'Blue')
|
||||
X = Class('enums::X', 'enums.h')
|
||||
rename(X.choices.bad, 'Bad')
|
||||
rename(X.choices.good, 'Good')
|
||||
rename(X.choices, 'Choices')
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace header_test {
|
||||
|
||||
enum choice { red, blue };
|
||||
|
||||
std::string choice_str(choice c)
|
||||
{
|
||||
std::map<choice, std::string> choice_map;
|
||||
choice_map[red] = "red";
|
||||
choice_map[blue] = "blue";
|
||||
return choice_map[c];
|
||||
}
|
||||
|
||||
struct C
|
||||
{
|
||||
choice c;
|
||||
|
||||
std::string get()
|
||||
{
|
||||
return choice_str(c);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
AllFromHeader('header_test.h')
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace nested {
|
||||
|
||||
struct X
|
||||
{
|
||||
struct Y
|
||||
{
|
||||
int valueY;
|
||||
static int staticYValue;
|
||||
struct Z
|
||||
{
|
||||
int valueZ;
|
||||
};
|
||||
};
|
||||
|
||||
static int staticXValue;
|
||||
int valueX;
|
||||
};
|
||||
|
||||
int X::staticXValue = 10;
|
||||
int X::Y::staticYValue = 20;
|
||||
|
||||
typedef X Root;
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Class('nested::Root', 'nested.h')
|
||||
@@ -1,43 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
namespace operators {
|
||||
|
||||
struct C
|
||||
{
|
||||
static double x;
|
||||
double value;
|
||||
|
||||
const C operator+(const C other) const
|
||||
{
|
||||
C c;
|
||||
c.value = value + other.value;
|
||||
return c;
|
||||
}
|
||||
operator int() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
double operator()()
|
||||
{
|
||||
return C::x;
|
||||
}
|
||||
|
||||
double operator()(double other)
|
||||
{
|
||||
return C::x + other;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
double C::x = 10;
|
||||
|
||||
const C operator*(const C& lhs, const C& rhs)
|
||||
{
|
||||
C c;
|
||||
c.value = lhs.value * rhs.value;
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Class('operators::C', 'operators.h')
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace templates {
|
||||
|
||||
template <class X, class Y>
|
||||
struct Point
|
||||
{
|
||||
X x;
|
||||
Y y;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
Point = Template('templates::Point', 'templates.h')
|
||||
rename(Point.x, 'i')
|
||||
rename(Point.y, 'j')
|
||||
IPoint = Point('int double')
|
||||
FPoint = Point('double int', 'FPoint')
|
||||
rename(IPoint, 'IPoint')
|
||||
rename(IPoint.x, 'x')
|
||||
rename(IPoint.y, 'y')
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace unions {
|
||||
|
||||
class UnionTest
|
||||
{
|
||||
public:
|
||||
union // unions are not supported for now
|
||||
{
|
||||
int i;
|
||||
short s1;
|
||||
short s2;
|
||||
} mBad;
|
||||
|
||||
int mGood;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
UnionTest = Class('unions::UnionTest', 'unions.h')
|
||||
exclude(UnionTest.mBad)
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
struct C
|
||||
{
|
||||
public:
|
||||
virtual int f()
|
||||
{
|
||||
return f_abs();
|
||||
}
|
||||
|
||||
const char* get_name()
|
||||
{
|
||||
return name();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int f_abs() = 0;
|
||||
|
||||
private:
|
||||
virtual const char* name() { return "C"; }
|
||||
};
|
||||
|
||||
int call_f(C& c) { return c.f(); }
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Class('C', 'virtual.h')
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef WRAPPER_TEST
|
||||
#define WRAPPER_TEST
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace wrappertest {
|
||||
|
||||
std::vector<int> Range(int count)
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.reserve(count);
|
||||
for (int i = 0; i < count; ++i){
|
||||
v.push_back(i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
struct C
|
||||
{
|
||||
C() {}
|
||||
|
||||
std::vector<int> Mul(int value)
|
||||
{
|
||||
std::vector<int> res;
|
||||
res.reserve(value);
|
||||
std::vector<int>::const_iterator it;
|
||||
std::vector<int> v(Range(value));
|
||||
for (it = v.begin(); it != v.end(); ++it){
|
||||
res.push_back(*it * value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
Include('wrappertest_wrappers.h')
|
||||
|
||||
f = Function('wrappertest::Range', 'wrappertest.h')
|
||||
set_wrapper(f, 'RangeWrapper')
|
||||
|
||||
mul = Wrapper('MulWrapper',
|
||||
'''
|
||||
list MulWrapper(wrappertest::C& c, int value){
|
||||
return VectorToList(c.Mul(value));
|
||||
}
|
||||
'''
|
||||
)
|
||||
|
||||
C = Class('wrappertest::C', 'wrappertest.h')
|
||||
set_wrapper(C.Mul, mul)
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef WRAPPER_TEST_WRAPPERS
|
||||
#define WRAPPER_TEST_WRAPPERS
|
||||
|
||||
#include <vector>
|
||||
#include <boost/python.hpp>
|
||||
#include "wrappertest.h"
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
template <class T>
|
||||
list VectorToList(const std::vector<T> & v)
|
||||
{
|
||||
list res;
|
||||
std::vector<T>::const_iterator it;
|
||||
for(it = v.begin(); it != v.end(); ++it){
|
||||
res.append(*it);
|
||||
}
|
||||
Py_XINCREF(res.ptr());
|
||||
return res;
|
||||
}
|
||||
|
||||
list RangeWrapper(int count){
|
||||
return VectorToList(wrappertest::Range(count));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
*.pyc
|
||||
@@ -1,742 +0,0 @@
|
||||
import exporters
|
||||
from Exporter import Exporter
|
||||
from declarations import *
|
||||
from enumerate import enumerate
|
||||
from settings import *
|
||||
from CodeUnit import CodeUnit
|
||||
from EnumExporter import EnumExporter
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassExporter
|
||||
#==============================================================================
|
||||
class ClassExporter(Exporter):
|
||||
'Generates boost.python code to export a class declaration'
|
||||
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
# sections of code
|
||||
self.sections = {}
|
||||
# template: each item in the list is an item into the class_<...>
|
||||
# section.
|
||||
self.sections['template'] = []
|
||||
# constructor: each item in the list is a parameter to the class_
|
||||
# constructor, like class_<C>(...)
|
||||
self.sections['constructor'] = []
|
||||
# inside: everything within the class_<> statement
|
||||
self.sections['inside'] = []
|
||||
# scope: items outside the class statement but within its scope.
|
||||
# scope* s = new scope(class<>());
|
||||
# ...
|
||||
# delete s;
|
||||
self.sections['scope'] = []
|
||||
# declarations: outside the BOOST_PYTHON_MODULE macro
|
||||
self.sections['declaration'] = []
|
||||
self.sections['include'] = []
|
||||
# a list of Constructor instances
|
||||
self.constructors = []
|
||||
self.wrapper_generator = None
|
||||
# a list of code units, generated by nested declarations
|
||||
self.nested_codeunits = []
|
||||
|
||||
|
||||
def ScopeName(self):
|
||||
return _ID(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.class_.FullName()
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
decl = self.GetDeclaration(self.info.name)
|
||||
if isinstance(decl, Typedef):
|
||||
self.class_ = self.GetDeclaration(decl.type.name)
|
||||
if not self.info.rename:
|
||||
self.info.rename = decl.name
|
||||
else:
|
||||
self.class_ = decl
|
||||
self.public_members = \
|
||||
[x for x in self.class_.members if x.visibility == Scope.public]
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Return the TOTAL number of bases that this class has, including the
|
||||
bases' bases. Do this because base classes must be instantialized
|
||||
before the derived classes in the module definition.
|
||||
'''
|
||||
|
||||
def BasesCount(classname):
|
||||
decl = self.GetDeclaration(classname)
|
||||
bases = [x.name for x in decl.bases]
|
||||
total = 0
|
||||
for base in bases:
|
||||
total += BasesCount(base)
|
||||
return len(bases) + total
|
||||
|
||||
return BasesCount(self.class_.FullName())
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
self.ExportBasics()
|
||||
self.ExportBases(exported_names)
|
||||
self.ExportConstructors()
|
||||
self.ExportVariables()
|
||||
self.ExportMethods()
|
||||
self.ExportVirtualMethods()
|
||||
self.ExportOperators()
|
||||
self.ExportNestedClasses(exported_names)
|
||||
self.ExportNestedEnums()
|
||||
self.Write(codeunit)
|
||||
|
||||
|
||||
def Write(self, codeunit):
|
||||
indent = self.INDENT
|
||||
boost_ns = namespaces.python
|
||||
pyste_ns = namespaces.pyste
|
||||
code = ''
|
||||
# begin a scope for this class if needed
|
||||
nested_codeunits = self.nested_codeunits
|
||||
needs_scope = self.sections['scope'] or nested_codeunits
|
||||
if needs_scope:
|
||||
scope_name = self.ScopeName()
|
||||
code += indent + boost_ns + 'scope* %s = new %sscope(\n' %\
|
||||
(scope_name, boost_ns)
|
||||
# export the template section
|
||||
template_params = ', '.join(self.sections['template'])
|
||||
code += indent + boost_ns + 'class_< %s >' % template_params
|
||||
# export the constructor section
|
||||
constructor_params = ', '.join(self.sections['constructor'])
|
||||
code += '(%s)\n' % constructor_params
|
||||
# export the inside section
|
||||
in_indent = indent*2
|
||||
for line in self.sections['inside']:
|
||||
code += in_indent + line + '\n'
|
||||
# write the scope section and end it
|
||||
if not needs_scope:
|
||||
code += indent + ';\n'
|
||||
else:
|
||||
code += indent + ');\n'
|
||||
for line in self.sections['scope']:
|
||||
code += indent + line + '\n'
|
||||
# write the contents of the nested classes
|
||||
for nested_unit in nested_codeunits:
|
||||
code += '\n' + nested_unit.Section('module')
|
||||
# close the scope
|
||||
code += indent + 'delete %s;\n' % scope_name
|
||||
|
||||
# write the code to the module section in the codeunit
|
||||
codeunit.Write('module', code + '\n')
|
||||
|
||||
# write the declarations to the codeunit
|
||||
declarations = '\n'.join(self.sections['declaration'])
|
||||
for nested_unit in nested_codeunits:
|
||||
declarations += nested_unit.Section('declaration')
|
||||
if declarations:
|
||||
codeunit.Write('declaration', declarations + '\n')
|
||||
|
||||
# write the includes to the codeunit
|
||||
includes = '\n'.join(self.sections['include'])
|
||||
for nested_unit in nested_codeunits:
|
||||
includes += nested_unit.Section('include')
|
||||
if includes:
|
||||
codeunit.Write('include', includes)
|
||||
|
||||
|
||||
def Add(self, section, item):
|
||||
'Add the item into the corresponding section'
|
||||
self.sections[section].append(item)
|
||||
|
||||
|
||||
def ExportBasics(self):
|
||||
'Export the name of the class and its class_ statement'
|
||||
self.Add('template', self.class_.FullName())
|
||||
name = self.info.rename or self.class_.name
|
||||
self.Add('constructor', '"%s"' % name)
|
||||
|
||||
|
||||
def ExportBases(self, exported_names):
|
||||
'Expose the bases of the class into the template section'
|
||||
bases = self.class_.bases
|
||||
bases_list = []
|
||||
for base in bases:
|
||||
if base.visibility == Scope.public and base.name in exported_names:
|
||||
bases_list.append(base.name)
|
||||
if bases_list:
|
||||
code = namespaces.python + 'bases< %s > ' % \
|
||||
(', '.join(bases_list))
|
||||
self.Add('template', code)
|
||||
|
||||
|
||||
def ExportConstructors(self):
|
||||
'''Exports all the public contructors of the class, plus indicates if the
|
||||
class is noncopyable.
|
||||
'''
|
||||
py_ns = namespaces.python
|
||||
indent = self.INDENT
|
||||
|
||||
def init_code(cons):
|
||||
'return the init<>() code for the given contructor'
|
||||
param_list = [p.FullName() for p in cons.parameters]
|
||||
min_params_list = param_list[:cons.minArgs]
|
||||
max_params_list = param_list[cons.minArgs:]
|
||||
min_params = ', '.join(min_params_list)
|
||||
max_params = ', '.join(max_params_list)
|
||||
init = py_ns + 'init< '
|
||||
init += min_params
|
||||
if max_params:
|
||||
if min_params:
|
||||
init += ', '
|
||||
init += py_ns + ('optional< %s >' % max_params)
|
||||
init += ' >()'
|
||||
return init
|
||||
|
||||
constructors = [x for x in self.public_members if isinstance(x, Constructor)]
|
||||
self.constructors = constructors[:]
|
||||
# don't export the copy constructor if the class is abstract
|
||||
if self.class_.abstract:
|
||||
for cons in constructors:
|
||||
if cons.IsCopy():
|
||||
constructors.remove(cons)
|
||||
break
|
||||
if not constructors:
|
||||
# declare no_init
|
||||
self.Add('constructor', py_ns + 'no_init')
|
||||
else:
|
||||
# write the constructor with less parameters to the constructor section
|
||||
smaller = None
|
||||
for cons in constructors:
|
||||
if smaller is None or len(cons.parameters) < len(smaller.parameters):
|
||||
smaller = cons
|
||||
assert smaller is not None
|
||||
self.Add('constructor', init_code(smaller))
|
||||
constructors.remove(smaller)
|
||||
# write the rest to the inside section, using def()
|
||||
for cons in constructors:
|
||||
code = '.def(%s)' % init_code(cons)
|
||||
self.Add('inside', code)
|
||||
# check if the class is copyable
|
||||
if not self.class_.HasCopyConstructor() or self.class_.abstract:
|
||||
self.Add('template', namespaces.boost + 'noncopyable')
|
||||
|
||||
|
||||
def ExportVariables(self):
|
||||
'Export the variables of the class, both static and simple variables'
|
||||
vars = [x for x in self.public_members if isinstance(x, Variable)]
|
||||
for var in vars:
|
||||
if self.info[var.name].exclude:
|
||||
continue
|
||||
name = self.info[var.name].rename or var.name
|
||||
fullname = var.FullName()
|
||||
if var.static:
|
||||
code = '%s->attr("%s") = %s;' % (self.ScopeName(), name, fullname)
|
||||
self.Add('scope', code)
|
||||
else:
|
||||
if var.type.const:
|
||||
def_ = '.def_readonly'
|
||||
else:
|
||||
def_ = '.def_readwrite'
|
||||
code = '%s("%s", &%s)' % (def_, name, fullname)
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
printed_policy_warnings = {}
|
||||
|
||||
def CheckPolicy(self, m):
|
||||
'Warns the user if this method needs a policy'
|
||||
def IsString(type):
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
needs_policy = isinstance(m.result, (ReferenceType, PointerType))
|
||||
if IsString(m.result):
|
||||
needs_policy = False
|
||||
has_policy = self.info[m.name].policy is not None
|
||||
if needs_policy and not has_policy:
|
||||
warning = '---> Error: Method "%s" needs a policy.' % m.FullName()
|
||||
if warning not in self.printed_policy_warnings:
|
||||
print warning
|
||||
print
|
||||
self.printed_policy_warnings[warning] = 1
|
||||
|
||||
|
||||
def ExportMethods(self):
|
||||
'Export all the non-virtual methods of this class'
|
||||
|
||||
def OverloadName(m):
|
||||
'Returns the name of the overloads struct for the given method'
|
||||
return _ID(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
|
||||
|
||||
declared = {}
|
||||
def DeclareOverloads(m):
|
||||
'Declares the macro for the generation of the overloads'
|
||||
if not m.virtual:
|
||||
func = m.name
|
||||
code = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(%s, %s, %i, %i)\n'
|
||||
code = code % (OverloadName(m), func, m.minArgs, m.maxArgs)
|
||||
if code not in declared:
|
||||
declared[code] = True
|
||||
self.Add('declaration', code)
|
||||
|
||||
|
||||
def Pointer(m):
|
||||
'returns the correct pointer declaration for the method m'
|
||||
# check if this method has a wrapper set for him
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if wrapper:
|
||||
return '&' + wrapper.FullName()
|
||||
# return normal pointers to the methods of the class
|
||||
is_unique = self.class_.IsUnique(m.name)
|
||||
if is_unique:
|
||||
return '&' + method.FullName()
|
||||
else:
|
||||
return method.PointerDeclaration()
|
||||
|
||||
def IsExportable(m):
|
||||
'Returns true if the given method is exportable by this routine'
|
||||
ignore = (Constructor, ClassOperator, Destructor)
|
||||
return isinstance(m, Method) and not isinstance(m, ignore) and not m.virtual
|
||||
|
||||
methods = [x for x in self.public_members if IsExportable(x)]
|
||||
|
||||
for method in methods:
|
||||
if self.info[method.name].exclude:
|
||||
continue # skip this method
|
||||
|
||||
name = self.info[method.name].rename or method.name
|
||||
|
||||
# warn the user if this method needs a policy and doesn't have one
|
||||
self.CheckPolicy(method)
|
||||
|
||||
# check for policies
|
||||
policy = self.info[method.name].policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
# check for overloads
|
||||
overload = ''
|
||||
if method.minArgs != method.maxArgs:
|
||||
# add the overloads for this method
|
||||
overload_name = OverloadName(method)
|
||||
DeclareOverloads(method)
|
||||
overload = ', %s%s()' % (namespaces.pyste, overload_name)
|
||||
|
||||
# build the .def string to export the method
|
||||
pointer = Pointer(method)
|
||||
code = '.def("%s", %s' % (name, pointer)
|
||||
code += policy
|
||||
code += overload
|
||||
code += ')'
|
||||
self.Add('inside', code)
|
||||
# static method
|
||||
if method.static:
|
||||
code = '.staticmethod("%s")' % name
|
||||
self.Add('inside', code)
|
||||
# add wrapper code if this method has one
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if wrapper and wrapper.code:
|
||||
self.Add('declaration', wrapper.code)
|
||||
|
||||
|
||||
def ExportVirtualMethods(self):
|
||||
# check if this class has any virtual methods
|
||||
has_virtual_methods = False
|
||||
for member in self.class_.members:
|
||||
if type(member) == Method and member.virtual:
|
||||
has_virtual_methods = True
|
||||
break
|
||||
|
||||
if has_virtual_methods:
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.info)
|
||||
self.Add('template', generator.FullName())
|
||||
for definition in generator.GenerateDefinitions():
|
||||
self.Add('inside', definition)
|
||||
self.Add('declaration', generator.GenerateVirtualWrapper(self.INDENT))
|
||||
|
||||
|
||||
# operators natively supported by boost
|
||||
BOOST_SUPPORTED_OPERATORS = '+ - * / % ^ & ! ~ | < > == != <= >= << >> && || += -='\
|
||||
'*= /= %= ^= &= |= <<= >>='.split()
|
||||
# create a map for faster lookup
|
||||
BOOST_SUPPORTED_OPERATORS = dict(zip(BOOST_SUPPORTED_OPERATORS, range(len(BOOST_SUPPORTED_OPERATORS))))
|
||||
|
||||
# a dict of operators that are not directly supported by boost, but can be exposed
|
||||
# simply as a function with a special signature
|
||||
BOOST_RENAME_OPERATORS = {
|
||||
'()' : '__call__',
|
||||
}
|
||||
|
||||
# converters which has a special name in python
|
||||
SPECIAL_CONVERTERS = {
|
||||
'double' : '__float__',
|
||||
'float' : '__float__',
|
||||
'int' : '__int__',
|
||||
'long' : '__long__',
|
||||
}
|
||||
|
||||
|
||||
def ExportOperators(self):
|
||||
'Export all member operators and free operators related to this class'
|
||||
|
||||
def GetFreeOperators():
|
||||
'Get all the free (global) operators related to this class'
|
||||
operators = []
|
||||
for decl in self.declarations:
|
||||
if isinstance(decl, Operator):
|
||||
# check if one of the params is this class
|
||||
for param in decl.parameters:
|
||||
if param.name == self.class_.FullName():
|
||||
operators.append(decl)
|
||||
break
|
||||
return operators
|
||||
|
||||
def GetOperand(param):
|
||||
'Returns the operand of this parameter (either "self", or "other<type>")'
|
||||
if param.name == self.class_.FullName():
|
||||
return namespaces.python + 'self'
|
||||
else:
|
||||
return namespaces.python + ('other< %s >()' % param.name)
|
||||
|
||||
|
||||
def HandleSpecialOperator(operator):
|
||||
# gatter information about the operator and its parameters
|
||||
result_name = operator.result.name
|
||||
param1_name = ''
|
||||
if operator.parameters:
|
||||
param1_name = operator.parameters[0].name
|
||||
|
||||
# check for str
|
||||
ostream = 'basic_ostream'
|
||||
is_str = result_name.find(ostream) != -1 and param1_name.find(ostream) != -1
|
||||
if is_str:
|
||||
namespace = namespaces.python + 'self_ns::'
|
||||
self_ = namespaces.python + 'self'
|
||||
return '.def(%sstr(%s))' % (namespace, self_)
|
||||
|
||||
# is not a special operator
|
||||
return None
|
||||
|
||||
|
||||
|
||||
frees = GetFreeOperators()
|
||||
members = [x for x in self.public_members if type(x) == ClassOperator]
|
||||
all_operators = frees + members
|
||||
operators = [x for x in all_operators if not self.info['operator'][x.name].exclude]
|
||||
|
||||
for operator in operators:
|
||||
# gatter information about the operator, for use later
|
||||
wrapper = self.info['operator'][operator.name].wrapper
|
||||
if wrapper:
|
||||
pointer = '&' + wrapper.FullName()
|
||||
if wrapper.code:
|
||||
self.Add('declaration', wrapper.code)
|
||||
elif isinstance(operator, ClassOperator) and self.class_.IsUnique(operator.name):
|
||||
pointer = '&' + operator.FullName()
|
||||
else:
|
||||
pointer = operator.PointerDeclaration()
|
||||
rename = self.info['operator'][operator.name].rename
|
||||
|
||||
# check if this operator will be exported as a method
|
||||
export_as_method = wrapper or rename or operator.name in self.BOOST_RENAME_OPERATORS
|
||||
|
||||
# check if this operator has a special representation in boost
|
||||
special_code = HandleSpecialOperator(operator)
|
||||
has_special_representation = special_code is not None
|
||||
|
||||
if export_as_method:
|
||||
# export this operator as a normal method, renaming or using the given wrapper
|
||||
if not rename:
|
||||
if wrapper:
|
||||
rename = wrapper.name
|
||||
else:
|
||||
rename = self.BOOST_RENAME_OPERATORS[operator.name]
|
||||
policy = ''
|
||||
policy_obj = self.info['operator'][operator.name].policy
|
||||
if policy_obj:
|
||||
policy = ', %s()' % policy_obj.Code()
|
||||
self.Add('inside', '.def("%s", %s%s)' % (rename, pointer, policy))
|
||||
|
||||
elif has_special_representation:
|
||||
self.Add('inside', special_code)
|
||||
|
||||
elif operator.name in self.BOOST_SUPPORTED_OPERATORS:
|
||||
# export this operator using boost's facilities
|
||||
op = operator
|
||||
is_unary = isinstance(op, Operator) and len(op.parameters) == 1 or\
|
||||
isinstance(op, ClassOperator) and len(op.parameters) == 0
|
||||
if is_unary:
|
||||
self.Add('inside', '.def( %s%sself )' % \
|
||||
(operator.name, namespaces.python))
|
||||
else:
|
||||
# binary operator
|
||||
if len(operator.parameters) == 2:
|
||||
left_operand = GetOperand(operator.parameters[0])
|
||||
right_operand = GetOperand(operator.parameters[1])
|
||||
else:
|
||||
left_operand = namespaces.python + 'self'
|
||||
right_operand = GetOperand(operator.parameters[0])
|
||||
self.Add('inside', '.def( %s %s %s )' % \
|
||||
(left_operand, operator.name, right_operand))
|
||||
|
||||
# export the converters.
|
||||
# export them as simple functions with a pre-determined name
|
||||
|
||||
converters = [x for x in self.public_members if type(x) == ConverterOperator]
|
||||
|
||||
def ConverterMethodName(converter):
|
||||
result_fullname = converter.result.name
|
||||
if result_fullname in self.SPECIAL_CONVERTERS:
|
||||
return self.SPECIAL_CONVERTERS[result_fullname]
|
||||
else:
|
||||
# extract the last name from the full name
|
||||
result_name = _ID(result_fullname.split('::')[-1])
|
||||
return 'to_' + result_name
|
||||
|
||||
for converter in converters:
|
||||
info = self.info['operator'][converter.result.name]
|
||||
# check if this operator should be excluded
|
||||
if info.exclude:
|
||||
continue
|
||||
|
||||
special_code = HandleSpecialOperator(converter)
|
||||
if info.rename or not special_code:
|
||||
# export as method
|
||||
name = info.rename or ConverterMethodName(converter)
|
||||
if self.class_.IsUnique(converter.name):
|
||||
pointer = '&' + converter.FullName()
|
||||
else:
|
||||
pointer = converter.PointerDeclaration()
|
||||
policy_code = ''
|
||||
if info.policy:
|
||||
policy_code = ', %s()' % info.policy.Code()
|
||||
self.Add('inside', '.def("%s", %s%s)' % (name, pointer, policy_code))
|
||||
|
||||
elif special_code:
|
||||
self.Add('inside', special_code)
|
||||
|
||||
|
||||
|
||||
def ExportNestedClasses(self, exported_names):
|
||||
nested_classes = [x for x in self.public_members if isinstance(x, NestedClass)]
|
||||
for nested_class in nested_classes:
|
||||
nested_info = self.info[nested_class.name]
|
||||
nested_info.include = self.info.include
|
||||
nested_info.name = nested_class.FullName()
|
||||
exporter = ClassExporter(nested_info)
|
||||
exporter.SetDeclarations(self.declarations + [nested_class])
|
||||
codeunit = CodeUnit(None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
def ExportNestedEnums(self):
|
||||
nested_enums = [x for x in self.public_members if isinstance(x, ClassEnumeration)]
|
||||
for enum in nested_enums:
|
||||
enum_info = self.info[enum.name]
|
||||
enum_info.include = self.info.include
|
||||
enum_info.name = enum.FullName()
|
||||
exporter = EnumExporter(enum_info)
|
||||
exporter.SetDeclarations(self.declarations + [enum])
|
||||
codeunit = CodeUnit(None)
|
||||
exporter.Export(codeunit, None)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
|
||||
|
||||
def _ID(name):
|
||||
'Returns the name as a valid identifier'
|
||||
for invalidchar in ('::', '<', '>', ' ', ','):
|
||||
name = name.replace(invalidchar, '_')
|
||||
# avoid duplications of '_' chars
|
||||
names = [x for x in name.split('_') if x]
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Virtual Wrapper utils
|
||||
#==============================================================================
|
||||
|
||||
def _ParamsInfo(m, count=None):
|
||||
if count is None:
|
||||
count = len(m.parameters)
|
||||
param_names = ['p%i' % i for i in range(count)]
|
||||
param_types = [x.FullName() for x in m.parameters[:count]]
|
||||
params = ['%s %s' % (t, n) for t, n in zip(param_types, param_names)]
|
||||
#for i, p in enumerate(m.parameters[:count]):
|
||||
# if p.default is not None:
|
||||
# #params[i] += '=%s' % p.default
|
||||
# params[i] += '=%s' % (p.name + '()')
|
||||
params = ', '.join(params)
|
||||
return params, param_names, param_types
|
||||
|
||||
|
||||
class _VirtualWrapperGenerator(object):
|
||||
'Generates code to export the virtual methods of the given class'
|
||||
|
||||
def __init__(self, class_, info):
|
||||
self.class_ = class_
|
||||
self.info = info
|
||||
self.wrapper_name = _ID(class_.FullName()) + '_Wrapper'
|
||||
|
||||
|
||||
def DefaultImplementationNames(self, method):
|
||||
'''Returns a list of default implementations for this method, one for each
|
||||
number of default arguments. Always returns at least one name, and return from
|
||||
the one with most arguments to the one with the least.
|
||||
'''
|
||||
base_name = 'default_' + method.name
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
if minArgs == maxArgs:
|
||||
return [base_name]
|
||||
else:
|
||||
return [base_name + ('_%i' % i) for i in range(minArgs, maxArgs+1)]
|
||||
|
||||
|
||||
def Declaration(self, method, indent):
|
||||
'''Returns a string with the declarations of the virtual wrapper and
|
||||
its default implementations. This string must be put inside the Wrapper
|
||||
body.
|
||||
'''
|
||||
pyste = namespaces.pyste
|
||||
python = namespaces.python
|
||||
rename = self.info[method.name].rename or method.name
|
||||
result = method.result.FullName()
|
||||
return_str = 'return '
|
||||
if result == 'void':
|
||||
return_str = ''
|
||||
params, param_names, param_types = _ParamsInfo(method)
|
||||
constantness = ''
|
||||
if method.const:
|
||||
constantness = ' const'
|
||||
|
||||
# call_method callback
|
||||
decl = indent + '%s %s(%s)%s {\n' % (result, method.name, params, constantness)
|
||||
param_names_str = ', '.join(param_names)
|
||||
if param_names_str:
|
||||
param_names_str = ', ' + param_names_str
|
||||
decl += indent*2 + '%s%scall_method< %s >(self, "%s"%s);\n' %\
|
||||
(return_str, python, result, rename, param_names_str)
|
||||
decl += indent + '}\n'
|
||||
|
||||
# default implementations (with overloading)
|
||||
# only for classes that are not abstract, and public methods
|
||||
if not method.abstract and method.visibility == Scope.public:
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
impl_names = self.DefaultImplementationNames(method)
|
||||
for impl_name, argNum in zip(impl_names, range(minArgs, maxArgs+1)):
|
||||
params, param_names, param_types = _ParamsInfo(method, argNum)
|
||||
decl += '\n'
|
||||
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
|
||||
decl += indent*2 + '%s%s::%s(%s);\n' % \
|
||||
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
|
||||
decl += indent + '}\n'
|
||||
return decl
|
||||
|
||||
|
||||
def MethodDefinition(self, method):
|
||||
'''Returns a list of lines, which should be put inside the class_
|
||||
statement to export this method.'''
|
||||
# dont define abstract methods
|
||||
pyste = namespaces.pyste
|
||||
rename = self.info[method.name].rename or method.name
|
||||
default_names = self.DefaultImplementationNames(method)
|
||||
class_name = self.class_.FullName()
|
||||
wrapper_name = pyste + self.wrapper_name
|
||||
result = method.result.FullName()
|
||||
is_method_unique = self.class_.IsUnique(method.name)
|
||||
constantness = ''
|
||||
if method.const:
|
||||
constantness = ' const'
|
||||
|
||||
# create a list of default-impl pointers
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
if is_method_unique:
|
||||
default_pointers = ['&%s::%s' % (wrapper_name, x) for x in default_names]
|
||||
else:
|
||||
default_pointers = []
|
||||
for impl_name, argNum in zip(default_names, range(minArgs, maxArgs+1)):
|
||||
param_list = [x.FullName() for x in method.parameters[:argNum]]
|
||||
params = ', '.join(param_list)
|
||||
signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
|
||||
default_pointer = '(%s)%s::%s' % (signature, wrapper_name, impl_name)
|
||||
default_pointers.append(default_pointer)
|
||||
|
||||
# get the pointer of the method
|
||||
if is_method_unique:
|
||||
pointer = '&' + method.FullName()
|
||||
else:
|
||||
pointer = method.PointerDeclaration()
|
||||
|
||||
# generate the defs
|
||||
definitions = []
|
||||
# basic def
|
||||
definitions.append('.def("%s", %s, %s)' % (rename, pointer, default_pointers[-1]))
|
||||
for default_pointer in default_pointers[:-1]:
|
||||
definitions.append('.def("%s", %s)' % (rename, default_pointer))
|
||||
return definitions
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return namespaces.pyste + self.wrapper_name
|
||||
|
||||
|
||||
def VirtualMethods(self):
|
||||
def IsVirtual(m):
|
||||
return type(m) == Method and m.virtual
|
||||
return [m for m in self.class_.members if IsVirtual(m)]
|
||||
|
||||
|
||||
|
||||
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)]
|
||||
|
||||
|
||||
def GenerateDefinitions(self):
|
||||
defs = []
|
||||
for method in self.VirtualMethods():
|
||||
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:
|
||||
defs.extend(self.MethodDefinition(method))
|
||||
return defs
|
||||
|
||||
|
||||
def GenerateVirtualWrapper(self, indent):
|
||||
'Return the wrapper for this class'
|
||||
|
||||
# generate the class code
|
||||
class_name = self.class_.FullName()
|
||||
code = 'struct %s: %s\n' % (self.wrapper_name, class_name)
|
||||
code += '{\n'
|
||||
# generate constructors (with the overloads for each one)
|
||||
for cons in self.Constructors(): # only public constructors
|
||||
minArgs = cons.minArgs
|
||||
maxArgs = cons.maxArgs
|
||||
# from the min number of arguments to the max number, generate
|
||||
# all version of the given constructor
|
||||
cons_code = ''
|
||||
for argNum in range(minArgs, maxArgs+1):
|
||||
params, param_names, param_types = _ParamsInfo(cons, argNum)
|
||||
if params:
|
||||
params = ', ' + params
|
||||
cons_code += indent + '%s(PyObject* self_%s):\n' % \
|
||||
(self.wrapper_name, params)
|
||||
cons_code += indent*2 + '%s(%s), self(self_) {}\n\n' % \
|
||||
(class_name, ', '.join(param_names))
|
||||
code += cons_code
|
||||
# generate the body
|
||||
body = []
|
||||
for method in self.VirtualMethods():
|
||||
if not self.info[method.name].exclude:
|
||||
body.append(self.Declaration(method, indent))
|
||||
body = '\n'.join(body)
|
||||
code += body + '\n'
|
||||
# add the self member
|
||||
code += indent + 'PyObject* self;\n'
|
||||
code += '};\n'
|
||||
return code
|
||||
@@ -1,78 +0,0 @@
|
||||
from settings import *
|
||||
|
||||
#==============================================================================
|
||||
# RemoveDuplicatedLines
|
||||
#==============================================================================
|
||||
def RemoveDuplicatedLines(text):
|
||||
includes = text.splitlines()
|
||||
d = dict([(include, 0) for include in includes])
|
||||
return '\n'.join(d.keys())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CodeUnit
|
||||
#==============================================================================
|
||||
class CodeUnit:
|
||||
'''
|
||||
Represents a cpp file, where other objects can write in one of the
|
||||
predefined sections.
|
||||
The avaiable sections are:
|
||||
include - The include area of the cpp file
|
||||
declaration - The part before the module definition
|
||||
module - Inside the BOOST_PYTHON_MODULE macro
|
||||
'''
|
||||
|
||||
USING_BOOST_NS = True
|
||||
|
||||
def __init__(self, modulename):
|
||||
self.modulename = modulename
|
||||
# define the avaiable sections
|
||||
self.code = {}
|
||||
self.code['include'] = ''
|
||||
self.code['declaration'] = ''
|
||||
self.code['module'] = ''
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
'write the given code in the section of the code unit'
|
||||
if section not in self.code:
|
||||
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
|
||||
self.code[section] += code
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def Save(self, filename):
|
||||
'Writes this code unit to the filename'
|
||||
space = '\n\n'
|
||||
fout = file(filename, 'w')
|
||||
# includes
|
||||
includes = RemoveDuplicatedLines(self.code['include'])
|
||||
fout.write('\n' + self._leftEquals('Includes'))
|
||||
fout.write('#include <boost/python.hpp>\n')
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
# using
|
||||
if self.USING_BOOST_NS:
|
||||
fout.write(self._leftEquals('Using'))
|
||||
fout.write('using namespace boost::python;\n\n')
|
||||
# declarations
|
||||
if self.code['declaration']:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write(self._leftEquals('Declarations'))
|
||||
fout.write('namespace %s {\n\n\n' % pyste_namespace)
|
||||
fout.write(self.code['declaration'])
|
||||
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(self._leftEquals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n{\n' % self.modulename)
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
def _leftEquals(self, s):
|
||||
s = '// %s ' % s
|
||||
return s + ('='*(80-len(s))) + '\n'
|
||||
@@ -1,94 +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
|
||||
|
||||
|
||||
def _includeparams(self, filename):
|
||||
includes = self.includes[:]
|
||||
filedir = os.path.dirname(filename)
|
||||
if not filedir:
|
||||
filedir = '.'
|
||||
includes.insert(0, filedir)
|
||||
includes = ['-I "%s"' % x for x in includes]
|
||||
return ' '.join(includes)
|
||||
|
||||
|
||||
def _defineparams(self):
|
||||
defines = ['-D "%s"' % x for x in self.defines]
|
||||
return ' '.join(defines)
|
||||
|
||||
|
||||
def FindFileName(self, include):
|
||||
if os.path.isfile(include):
|
||||
return include
|
||||
for path in self.includes:
|
||||
filename = os.path.join(path, include)
|
||||
if os.path.isfile(filename):
|
||||
return filename
|
||||
name = os.path.basename(include)
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
|
||||
|
||||
def parse(self, include, symbols=None, tail=None):
|
||||
'''Parses the given filename, and returns (declaration, header). The
|
||||
header returned is normally the same as the given to this method,
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to gcc.
|
||||
This temp filename is then returned.
|
||||
'''
|
||||
filename = self.FindFileName(include)
|
||||
# copy file to temp folder, if needed
|
||||
if tail:
|
||||
tempfilename = tempfile.mktemp('.h')
|
||||
infilename = tempfilename
|
||||
shutil.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 symbols:
|
||||
cmd += ' -fxml-start=' + ','.join(symbols)
|
||||
status = os.system(cmd)
|
||||
if status != 0 or not os.path.isfile(xmlfile):
|
||||
raise CppParserError, 'Error executing gccxml'
|
||||
# parse the resulting xml
|
||||
declarations = ParseDeclarations(xmlfile)
|
||||
# return the declarations
|
||||
return declarations, infilename
|
||||
finally:
|
||||
if settings.DEBUG and os.path.isfile(xmlfile):
|
||||
filename = os.path.basename(include)
|
||||
shutil.copy(xmlfile, os.path.splitext(filename)[0] + '.xml')
|
||||
# delete the temporary files
|
||||
try:
|
||||
os.remove(xmlfile)
|
||||
if tail:
|
||||
os.remove(tempfilename)
|
||||
except OSError: pass
|
||||
@@ -1,30 +0,0 @@
|
||||
from Exporter import Exporter
|
||||
from settings import *
|
||||
|
||||
#==============================================================================
|
||||
# EnumExporter
|
||||
#==============================================================================
|
||||
class EnumExporter(Exporter):
|
||||
'Exports enumerators'
|
||||
|
||||
def __init__(self, info):
|
||||
Exporter.__init__(self, info)
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
self.enum = self.GetDeclaration(self.info.name)
|
||||
|
||||
|
||||
def Export(self, codeunit, expoted_names):
|
||||
indent = self.INDENT
|
||||
in_indent = self.INDENT*2
|
||||
rename = self.info.rename or self.enum.name
|
||||
full_name = self.enum.FullName()
|
||||
code = indent + namespaces.python + 'enum_< %s >("%s")\n' % (full_name, rename)
|
||||
for name in self.enum.values:
|
||||
rename = self.info[name].rename or name
|
||||
value_fullname = self.enum.ValueFullName(name)
|
||||
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
|
||||
code += indent + ';\n\n'
|
||||
codeunit.Write('module', code)
|
||||
@@ -1,69 +0,0 @@
|
||||
import os.path
|
||||
|
||||
#==============================================================================
|
||||
# Exporter
|
||||
#==============================================================================
|
||||
class Exporter:
|
||||
'Base class for objects capable to generate boost.python code.'
|
||||
|
||||
INDENT = ' ' * 4
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
self.info = info
|
||||
self.parser_tail = parser_tail
|
||||
|
||||
|
||||
def Parse(self, parser):
|
||||
self.parser = parser
|
||||
header = self.info.include
|
||||
tail = self.parser_tail
|
||||
declarations, parser_header = parser.parse(header, tail=tail)
|
||||
self.parser_header = parser_header
|
||||
self.SetDeclarations(declarations)
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
self.declarations = declarations
|
||||
|
||||
|
||||
def GenerateCode(self, codeunit, exported_names):
|
||||
self.WriteInclude(codeunit)
|
||||
self.Export(codeunit, exported_names)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
codeunit.Write('include', '#include <%s>\n' % self.info.include)
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
'subclasses must override this to do the real work'
|
||||
pass
|
||||
|
||||
|
||||
def Name(self):
|
||||
'''Returns the name of this Exporter. The name will be added to the
|
||||
list of names exported, which may have a use for other exporters.
|
||||
'''
|
||||
return None
|
||||
|
||||
|
||||
def GetDeclarations(self, fullname):
|
||||
decls = [x for x in self.declarations if x.FullName() == fullname]
|
||||
if not decls:
|
||||
raise RuntimeError, 'no %s declaration found!' % fullname
|
||||
return decls
|
||||
|
||||
|
||||
def GetDeclaration(self, fullname):
|
||||
decls = self.GetDeclarations(fullname)
|
||||
assert len(decls) == 1
|
||||
return decls[0]
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Returns a number that indicates to which order this exporter
|
||||
belongs. The exporters will be called from the lowest order to the
|
||||
highest order.
|
||||
This function will only be called after Parse has been called.
|
||||
'''
|
||||
return None # don't care
|
||||
@@ -1,85 +0,0 @@
|
||||
from Exporter import Exporter
|
||||
from policies import *
|
||||
from declarations import *
|
||||
from settings import *
|
||||
|
||||
|
||||
class FunctionExporter(Exporter):
|
||||
'Generates boost.python code to export the given function.'
|
||||
|
||||
def __init__(self, info, tail=None):
|
||||
Exporter.__init__(self, info, tail)
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
decls = self.GetDeclarations(self.info.name)
|
||||
for decl in decls:
|
||||
self.CheckPolicy(decl)
|
||||
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def CheckPolicy(self, func):
|
||||
'Warns the user if this function needs a policy'
|
||||
def IsString(type):
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
needs_policy = isinstance(func.result, (ReferenceType, PointerType))
|
||||
if IsString(func.result):
|
||||
needs_policy = False
|
||||
if needs_policy and self.info.policy is None:
|
||||
print '---> Error: Function "%s" needs a policy.' % func.FullName()
|
||||
print
|
||||
|
||||
def ExportDeclaration(self, decl, unique, codeunit):
|
||||
name = self.info.rename or decl.name
|
||||
defs = namespaces.python + 'def("%s", ' % name
|
||||
wrapper = self.info.wrapper
|
||||
if wrapper:
|
||||
pointer = '&' + wrapper.FullName()
|
||||
elif not unique:
|
||||
pointer = decl.PointerDeclaration()
|
||||
else:
|
||||
pointer = '&' + decl.FullName()
|
||||
defs += pointer
|
||||
defs += self.PolicyCode()
|
||||
overload = self.OverloadName(decl)
|
||||
if overload:
|
||||
defs += ', %s()' % (namespaces.pyste + overload)
|
||||
defs += ');'
|
||||
codeunit.Write('module', self.INDENT + defs + '\n')
|
||||
# add the code of the wrapper
|
||||
if wrapper and wrapper.code:
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
|
||||
|
||||
def OverloadName(self, decl):
|
||||
if decl.minArgs != decl.maxArgs:
|
||||
return '%s_overloads_%i_%i' % \
|
||||
(decl.name, decl.minArgs, decl.maxArgs)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def GenerateOverloads(self, declarations, codeunit):
|
||||
codes = {}
|
||||
for decl in declarations:
|
||||
overload = self.OverloadName(decl)
|
||||
if overload and overload not in codes:
|
||||
code = 'BOOST_PYTHON_FUNCTION_OVERLOADS(%s, %s, %i, %i)' %\
|
||||
(overload, decl.FullName(), decl.minArgs, decl.maxArgs)
|
||||
codeunit.Write('declaration', code + '\n')
|
||||
codes[overload] = None
|
||||
|
||||
|
||||
def PolicyCode(self):
|
||||
policy = self.info.policy
|
||||
if policy is not None:
|
||||
assert isinstance(policy, Policy)
|
||||
return ', %s()' % policy.Code()
|
||||
else:
|
||||
return ''
|
||||
|
||||
@@ -1,403 +0,0 @@
|
||||
from declarations import *
|
||||
from elementtree.ElementTree import ElementTree
|
||||
from xml.parsers.expat import ExpatError
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
class InvalidXMLError(Exception): pass
|
||||
|
||||
class ParserError(Exception): pass
|
||||
|
||||
class InvalidContextError(ParserError): pass
|
||||
|
||||
|
||||
class GCCXMLParser(object):
|
||||
'Parse a GCC_XML file and extract the top-level declarations.'
|
||||
|
||||
interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0}
|
||||
|
||||
def Parse(self, filename):
|
||||
self.elements = self.GetElementsFromXML(filename)
|
||||
# high level declarations
|
||||
self.declarations = []
|
||||
# parse the elements
|
||||
for id in self.elements:
|
||||
element, decl = self.elements[id]
|
||||
if decl is None:
|
||||
try:
|
||||
self.ParseElement(id, element)
|
||||
except InvalidContextError:
|
||||
pass # ignore those nodes with invalid context
|
||||
# (workaround gccxml bug)
|
||||
|
||||
|
||||
def Declarations(self):
|
||||
return self.declarations
|
||||
|
||||
|
||||
def AddDecl(self, decl):
|
||||
self.declarations.append(decl)
|
||||
|
||||
|
||||
def ParseElement(self, id, element):
|
||||
method = 'Parse' + element.tag
|
||||
if hasattr(self, method):
|
||||
func = getattr(self, method)
|
||||
func(id, element)
|
||||
|
||||
|
||||
def GetElementsFromXML(self,filename):
|
||||
'Extracts a dictionary of elements from the gcc_xml file.'
|
||||
|
||||
tree = ElementTree()
|
||||
try:
|
||||
tree.parse(filename)
|
||||
except ExpatError:
|
||||
raise InvalidXMLError, 'Not a XML file: %s' % filename
|
||||
|
||||
root = tree.getroot()
|
||||
if root.tag != 'GCC_XML':
|
||||
raise InvalidXMLError, 'Not a valid GCC_XML file'
|
||||
|
||||
# build a dictionary of id -> element, None
|
||||
elementlist = root.getchildren()
|
||||
elements = {}
|
||||
for element in elementlist:
|
||||
id = element.get('id')
|
||||
if id:
|
||||
elements[id] = element, None
|
||||
return elements
|
||||
|
||||
|
||||
def GetDecl(self, id):
|
||||
if id not in self.elements:
|
||||
if id == '_0':
|
||||
raise InvalidContextError, 'Invalid context found in the xml file.'
|
||||
else:
|
||||
msg = 'ID not found in elements: %s' % id
|
||||
raise ParserError, msg
|
||||
|
||||
elem, decl = self.elements[id]
|
||||
if decl is None:
|
||||
self.ParseElement(id, elem)
|
||||
elem, decl = self.elements[id]
|
||||
if decl is None:
|
||||
raise ParserError, 'Could not parse element: %s' % elem.tag
|
||||
return decl
|
||||
|
||||
|
||||
def GetType(self, id):
|
||||
const = False
|
||||
volatile = False
|
||||
if id[-1] == 'v':
|
||||
volatile = True
|
||||
id = id[:-1]
|
||||
if id[-1] == 'c':
|
||||
const = True
|
||||
id = id[:-1]
|
||||
decl = self.GetDecl(id)
|
||||
if isinstance(decl, Type):
|
||||
res = deepcopy(decl)
|
||||
if const:
|
||||
res.const = const
|
||||
if volatile:
|
||||
res.volatile = volatile
|
||||
else:
|
||||
res = Type(decl.FullName(), const)
|
||||
res.volatile = volatile
|
||||
return res
|
||||
|
||||
|
||||
def GetLocation(self, location):
|
||||
file, line = location.split(':')
|
||||
file = self.GetDecl(file)
|
||||
return file, int(line)
|
||||
|
||||
|
||||
def Update(self, id, decl):
|
||||
element, _ = self.elements[id]
|
||||
self.elements[id] = element, decl
|
||||
|
||||
|
||||
def ParseNamespace(self, id, element):
|
||||
namespace = element.get('name')
|
||||
context = element.get('context')
|
||||
if context:
|
||||
outerns = self.GetDecl(context)
|
||||
if not outerns.endswith('::'):
|
||||
outerns += '::'
|
||||
namespace = outerns + namespace
|
||||
if namespace.startswith('::'):
|
||||
namespace = namespace[2:]
|
||||
self.Update(id, namespace)
|
||||
|
||||
|
||||
def ParseFile(self, id, element):
|
||||
filename = element.get('name')
|
||||
self.Update(id, filename)
|
||||
|
||||
|
||||
def ParseVariable(self, id, element):
|
||||
# in gcc_xml, a static Field is declared as a Variable, so we check
|
||||
# this and call the Field parser if apply.
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, Class):
|
||||
self.ParseField(id, element)
|
||||
elem, decl = self.elements[id]
|
||||
decl.static = True
|
||||
else:
|
||||
namespace = context
|
||||
name = element.get('name')
|
||||
type_ = self.GetType(element.get('type'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
variable = Variable(type_, name, namespace)
|
||||
variable.location = location
|
||||
self.AddDecl(variable)
|
||||
self.Update(id, variable)
|
||||
|
||||
|
||||
def GetArguments(self, element):
|
||||
args = []
|
||||
for child in element:
|
||||
if child.tag == 'Argument':
|
||||
type_ = self.GetType(child.get('type'))
|
||||
type_.default = child.get('default')
|
||||
args.append(type_)
|
||||
return args
|
||||
|
||||
|
||||
def ParseFunction(self, id, element, functionType=Function):
|
||||
'''functionType is used because a Operator is identical to a normal
|
||||
function, only the type of the function changes.'''
|
||||
name = element.get('name')
|
||||
returns = self.GetType(element.get('returns'))
|
||||
namespace = self.GetDecl(element.get('context'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
function = functionType(name, namespace, returns, params)
|
||||
function.location = location
|
||||
self.AddDecl(function)
|
||||
self.Update(id, function)
|
||||
|
||||
|
||||
def ParseOperatorFunction(self, id, element):
|
||||
self.ParseFunction(id, element, Operator)
|
||||
|
||||
|
||||
def GetBases(self, bases):
|
||||
'Parses the string "bases" from the xml into a list of Base instances.'
|
||||
|
||||
if bases is None:
|
||||
return []
|
||||
bases = bases.split()
|
||||
baseobjs = []
|
||||
for base in bases:
|
||||
# get the visibility
|
||||
split = base.split(':')
|
||||
if len(split) == 2:
|
||||
visib = split[0]
|
||||
base = split[1]
|
||||
else:
|
||||
visib = Scope.public
|
||||
decl = self.GetDecl(base)
|
||||
baseobj = Base(decl.FullName(), visib)
|
||||
baseobjs.append(baseobj)
|
||||
return baseobjs
|
||||
|
||||
|
||||
def GetMembers(self, members):
|
||||
# members must be a string with the ids of the members
|
||||
if members is None:
|
||||
return []
|
||||
memberobjs = []
|
||||
for member in members.split():
|
||||
memberobjs.append(self.GetDecl(member))
|
||||
return memberobjs
|
||||
|
||||
|
||||
def ParseClass(self, id, element):
|
||||
name = element.get('name')
|
||||
abstract = bool(int(element.get('abstract', '0')))
|
||||
bases = self.GetBases(element.get('bases'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, str):
|
||||
class_ = Class(name, context, [], abstract, bases)
|
||||
self.AddDecl(class_)
|
||||
else:
|
||||
# a nested class
|
||||
visib = element.get('access', Scope.public)
|
||||
class_ = NestedClass(
|
||||
name, context.FullName(), visib, [], abstract, bases)
|
||||
# we have to add the declaration of the class before trying
|
||||
# to parse its members, to avoid recursion.
|
||||
class_.location = location
|
||||
self.Update(id, class_)
|
||||
# now we can get the members
|
||||
class_.members = self.GetMembers(element.get('members'))
|
||||
|
||||
|
||||
def ParseStruct(self, id, element):
|
||||
self.ParseClass(id, element)
|
||||
|
||||
|
||||
def ParseFundamentalType(self, id, element):
|
||||
name = element.get('name')
|
||||
type_ = FundamentalType(name)
|
||||
self.Update(id, type_)
|
||||
|
||||
|
||||
def ParseArrayType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
min = element.get('min')
|
||||
max = element.get('max')
|
||||
array = ArrayType(type_.name, min, max, type_.const)
|
||||
self.Update(id, array)
|
||||
|
||||
|
||||
def ParseReferenceType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = ReferenceType(type_.name, type_.const, None, expand)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
def ParsePointerType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = PointerType(type_.name, type_.const, None, expand)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
def ParseFunctionType(self, id, element):
|
||||
result = self.GetType(element.get('returns'))
|
||||
args = self.GetArguments(element)
|
||||
func = FunctionType(result, args)
|
||||
self.Update(id, func)
|
||||
|
||||
|
||||
def ParseMethodType(self, id, element):
|
||||
class_ = self.GetDecl(element.get('basetype')).FullName()
|
||||
result = self.GetType(element.get('returns'))
|
||||
args = self.GetArguments(element)
|
||||
method = MethodType(result, args, class_)
|
||||
self.Update(id, method)
|
||||
|
||||
|
||||
def ParseField(self, id, element):
|
||||
name = element.get('name')
|
||||
visib = element.get('access', Scope.public)
|
||||
classname = self.GetDecl(element.get('context')).FullName()
|
||||
type_ = self.GetType(element.get('type'))
|
||||
static = bool(int(element.get('extern', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
var = ClassVariable(type_, name, classname, visib, static)
|
||||
var.location = location
|
||||
self.Update(id, var)
|
||||
|
||||
|
||||
def ParseMethod(self, id, element, methodType=Method):
|
||||
name = element.get('name')
|
||||
result = self.GetType(element.get('returns'))
|
||||
classname = self.GetDecl(element.get('context')).FullName()
|
||||
visib = element.get('access', Scope.public)
|
||||
static = bool(int(element.get('static', '0')))
|
||||
virtual = bool(int(element.get('virtual', '0')))
|
||||
abstract = bool(int(element.get('pure_virtual', '0')))
|
||||
const = bool(int(element.get('const', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
method = methodType(
|
||||
name, classname, result, params, visib, virtual, abstract, static, const)
|
||||
method.location = location
|
||||
self.Update(id, method)
|
||||
|
||||
|
||||
def ParseOperatorMethod(self, id, element):
|
||||
self.ParseMethod(id, element, ClassOperator)
|
||||
|
||||
|
||||
def ParseConstructor(self, id, element):
|
||||
name = element.get('name')
|
||||
visib = element.get('access', Scope.public)
|
||||
classname = self.GetDecl(element.get('context')).FullName()
|
||||
location = self.GetLocation(element.get('location'))
|
||||
params = self.GetArguments(element)
|
||||
ctor = Constructor(name, classname, params, visib)
|
||||
ctor.location = location
|
||||
self.Update(id, ctor)
|
||||
|
||||
|
||||
def ParseDestructor(self, id, element):
|
||||
name = element.get('name')
|
||||
visib = element.get('access', Scope.public)
|
||||
classname = self.GetDecl(element.get('context')).FullName()
|
||||
virtual = bool(int(element.get('virtual', '0')))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
des = Destructor(name, classname, visib, virtual)
|
||||
des.location = location
|
||||
self.Update(id, des)
|
||||
|
||||
|
||||
def ParseConverter(self, id, element):
|
||||
self.ParseMethod(id, element, ConverterOperator)
|
||||
|
||||
|
||||
def ParseTypedef(self, id, element):
|
||||
name = element.get('name')
|
||||
type = self.GetType(element.get('type'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
if isinstance(context, Class):
|
||||
context = context.FullName()
|
||||
typedef = Typedef(type, name, context)
|
||||
self.Update(id, typedef)
|
||||
self.AddDecl(typedef)
|
||||
|
||||
|
||||
def ParseEnumeration(self, id, element):
|
||||
name = element.get('name')
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
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)
|
||||
|
||||
enum.location = location
|
||||
for child in element:
|
||||
if child.tag == 'EnumValue':
|
||||
name = child.get('name')
|
||||
value = int(child.get('init'))
|
||||
enum.values[name] = value
|
||||
self.Update(id, enum)
|
||||
|
||||
|
||||
def ParseUnimplemented(self, id, element):
|
||||
'No idea of what this is'
|
||||
self.Update(id, Declaration('', ''))
|
||||
|
||||
|
||||
def ParseUnion(self, id, element):
|
||||
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.'
|
||||
|
||||
parser = GCCXMLParser()
|
||||
parser.Parse(filename)
|
||||
return parser.Declarations()
|
||||
@@ -1,67 +0,0 @@
|
||||
from Exporter import Exporter
|
||||
from ClassExporter import ClassExporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from infos import *
|
||||
from declarations import *
|
||||
import os.path
|
||||
import exporters
|
||||
|
||||
#==============================================================================
|
||||
# HeaderExporter
|
||||
#==============================================================================
|
||||
class HeaderExporter(Exporter):
|
||||
'Exports all declarations found in the given header'
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
|
||||
|
||||
def WriteInclude(self, codeunit):
|
||||
pass
|
||||
|
||||
|
||||
def SetDeclarations(self, declarations):
|
||||
def IsInternalName(name):
|
||||
'''Returns true if the given name looks like a internal compiler
|
||||
structure'''
|
||||
return name.startswith('__')
|
||||
|
||||
Exporter.SetDeclarations(self, declarations)
|
||||
header = os.path.normpath(self.parser_header)
|
||||
for decl in declarations:
|
||||
# check if this declaration is in the header
|
||||
location = os.path.normpath(decl.location[0])
|
||||
if location != header or IsInternalName(decl.name):
|
||||
continue
|
||||
# ok, check the type of the declaration and export it accordingly
|
||||
self.HandleDeclaration(decl)
|
||||
|
||||
|
||||
def HandleDeclaration(self, decl):
|
||||
'''Dispatch the declaration to the appropriate method, that must create
|
||||
a suitable info object for a Exporter, create a Exporter, set its
|
||||
declarations and append it to the list of exporters.
|
||||
'''
|
||||
dispatch_table = {
|
||||
Class : ClassExporter,
|
||||
Enumeration : EnumExporter,
|
||||
Function : FunctionExporter,
|
||||
}
|
||||
|
||||
for decl_type, exporter_type in dispatch_table.items():
|
||||
if type(decl) == decl_type:
|
||||
self.HandleExporter(decl, exporter_type)
|
||||
break
|
||||
|
||||
|
||||
def HandleExporter(self, decl, exporter_type):
|
||||
info = self.info[decl.name]
|
||||
info.name = decl.FullName()
|
||||
info.include = self.info.include
|
||||
exporter = exporter_type(info)
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import os.path
|
||||
from Exporter import Exporter
|
||||
|
||||
#==============================================================================
|
||||
# IncludeExporter
|
||||
#==============================================================================
|
||||
class IncludeExporter(Exporter):
|
||||
'''Writes an include declaration to the module. Useful to add extra code
|
||||
for use in the Wrappers.
|
||||
This class just reimplements the Parse method to do nothing: the
|
||||
WriteInclude in Exporter already does the work for us.
|
||||
'''
|
||||
|
||||
def __init__(self, info, parser_tail=None):
|
||||
Exporter.__init__(self, info, parser_tail)
|
||||
|
||||
def Parse(self, parser):
|
||||
pass
|
||||
|
||||
@@ -1,464 +0,0 @@
|
||||
'''
|
||||
Module declarations
|
||||
|
||||
Defines classes that represent declarations found in C++ header files.
|
||||
|
||||
'''
|
||||
|
||||
class Declaration(object):
|
||||
'Represents a basic declaration.'
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
# the declaration name
|
||||
self.name = name
|
||||
# all the namespaces, separated by '::' = 'boost::inner'
|
||||
self.namespace = namespace
|
||||
# tuple (filename, line)
|
||||
self.location = '', -1
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'Returns the full qualified name: "boost::inner::Test"'
|
||||
namespace = self.namespace or ''
|
||||
#if not namespace:
|
||||
# namespace = ''
|
||||
if namespace and not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + self.name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '<Declaration %s at %s>' % (self.FullName(), id(self))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return 'Declaration of %s' % self.FullName()
|
||||
|
||||
|
||||
|
||||
class Class(Declaration):
|
||||
'The declaration of a class or struct.'
|
||||
|
||||
def __init__(self, name, namespace, members, abstract, bases):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# list of members
|
||||
self.members = members
|
||||
# whatever the class has any abstract methods
|
||||
self.abstract = abstract
|
||||
# instances of Base
|
||||
self.bases = bases
|
||||
self._members_count = {}
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.members)
|
||||
|
||||
|
||||
def IsAbstract(self):
|
||||
'Returns True if any method of this class is abstract'
|
||||
for member in self.members:
|
||||
if isinstance(member, Method):
|
||||
if member.abstract:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def RawName(self):
|
||||
'Returns the raw name of a template class. name = Foo<int>, raw = Foo'
|
||||
lesspos = self.name.find('<')
|
||||
if lesspos != -1:
|
||||
return self.name[:lesspos]
|
||||
else:
|
||||
return self.name
|
||||
|
||||
|
||||
def Constructors(self, publics_only=True):
|
||||
constructors = []
|
||||
for member in self:
|
||||
if isinstance(member, Constructor):
|
||||
if publics_only and member.visibility != Scope.public:
|
||||
continue
|
||||
constructors.append(member)
|
||||
return constructors
|
||||
|
||||
|
||||
def HasCopyConstructor(self):
|
||||
for cons in self.Constructors():
|
||||
if cons.IsCopy():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def HasDefaultConstructor(self):
|
||||
for cons in self.Constructors():
|
||||
if cons.IsDefault():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def IsUnique(self, member_name):
|
||||
if not self._members_count:
|
||||
for m in self:
|
||||
self._members_count[m.name] = self._members_count.get(m.name, 0) + 1
|
||||
try:
|
||||
return self._members_count[member_name] == 1
|
||||
except KeyError:
|
||||
print self._members_count
|
||||
print 'Key', member_name
|
||||
|
||||
|
||||
|
||||
class NestedClass(Class):
|
||||
'The declaration of a class/struct inside another class/struct.'
|
||||
|
||||
def __init__(self, name, class_, visib, members, abstract, bases):
|
||||
Class.__init__(self, name, None, members, abstract, bases)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
|
||||
class Base:
|
||||
'Represents a base class of another class.'
|
||||
|
||||
def __init__(self, name, visibility=None):
|
||||
# class_ is the full name of the base class
|
||||
self.name = name
|
||||
# visibility of the derivation
|
||||
if visibility is None:
|
||||
visibility = Scope.public
|
||||
self.visibility = visibility
|
||||
|
||||
|
||||
|
||||
class Scope:
|
||||
public = 'public'
|
||||
private = 'private'
|
||||
protected = 'protected'
|
||||
|
||||
|
||||
|
||||
class Function(Declaration):
|
||||
'The declaration of a function.'
|
||||
|
||||
def __init__(self, name, namespace, result, params):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# the result type: instance of Type, or None (constructors)
|
||||
self.result = result
|
||||
# the parameters: instances of Type
|
||||
self.parameters = params
|
||||
|
||||
|
||||
def PointerDeclaration(self):
|
||||
'returns a declaration of a pointer to this function'
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
return '(%s (*)(%s))&%s' % (result, params, self.FullName())
|
||||
|
||||
|
||||
def _MinArgs(self):
|
||||
min = 0
|
||||
for arg in self.parameters:
|
||||
if arg.default is None:
|
||||
min += 1
|
||||
return min
|
||||
|
||||
minArgs = property(_MinArgs)
|
||||
|
||||
|
||||
def _MaxArgs(self):
|
||||
return len(self.parameters)
|
||||
|
||||
maxArgs = property(_MaxArgs)
|
||||
|
||||
|
||||
|
||||
class Operator(Function):
|
||||
'The declaration of a custom operator.'
|
||||
def FullName(self):
|
||||
namespace = self.namespace or ''
|
||||
if not namespace.endswith('::'):
|
||||
namespace += '::'
|
||||
return namespace + 'operator' + self.name
|
||||
|
||||
|
||||
|
||||
class Method(Function):
|
||||
'The declaration of a method.'
|
||||
|
||||
def __init__(self, name, class_, result, params, visib, virtual, abstract, static, const):
|
||||
Function.__init__(self, name, None, result, params)
|
||||
self.visibility = visib
|
||||
self.virtual = virtual
|
||||
self.abstract = abstract
|
||||
self.static = static
|
||||
self.class_ = class_
|
||||
self.const = const
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::' + self.name
|
||||
|
||||
|
||||
def PointerDeclaration(self):
|
||||
'returns a declaration of a pointer to this function'
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s)&%s' %\
|
||||
(result, self.class_, params, const, self.FullName())
|
||||
|
||||
|
||||
class Constructor(Method):
|
||||
'A constructor of a class.'
|
||||
|
||||
def __init__(self, name, class_, params, visib):
|
||||
Method.__init__(self, name, class_, None, params, visib, False, False, False, False)
|
||||
|
||||
|
||||
def IsDefault(self):
|
||||
return len(self.parameters) == 0
|
||||
|
||||
|
||||
def IsCopy(self):
|
||||
if len(self.parameters) != 1:
|
||||
return False
|
||||
param = self.parameters[0]
|
||||
class_as_param = self.parameters[0].name == self.class_
|
||||
param_reference = isinstance(param, ReferenceType)
|
||||
return param_reference and class_as_param and param.const
|
||||
|
||||
|
||||
class Destructor(Method):
|
||||
'The destructor of a class.'
|
||||
|
||||
def __init__(self, name, class_, visib, virtual):
|
||||
Method.__init__(self, name, class_, None, [], visib, virtual, False, False, False)
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::~' + self.name
|
||||
|
||||
|
||||
|
||||
class ClassOperator(Method):
|
||||
'The declaration of a custom operator in a class.'
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::operator ' + self.name
|
||||
|
||||
|
||||
|
||||
class ConverterOperator(ClassOperator):
|
||||
'An operator in the form "operator OtherClass()".'
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::operator ' + self.result.name
|
||||
|
||||
|
||||
|
||||
class Type(Declaration):
|
||||
'Represents a type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
self.const = const
|
||||
# used when the Type is a function argument
|
||||
self.default = default
|
||||
self.volatile = False
|
||||
|
||||
def __repr__(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return '<Type ' + const + self.name + '>'
|
||||
|
||||
|
||||
def FullName(self):
|
||||
if self.const:
|
||||
const = 'const '
|
||||
else:
|
||||
const = ''
|
||||
return const + self.name
|
||||
|
||||
|
||||
|
||||
class ArrayType(Type):
|
||||
'Represents an array.'
|
||||
|
||||
def __init__(self, name, min, max, const=False):
|
||||
'min and max can be None.'
|
||||
Type.__init__(self, name, const)
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
|
||||
|
||||
class ReferenceType(Type):
|
||||
'A reference type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, expandRef=True):
|
||||
Type.__init__(self, name, const, default)
|
||||
self.expand = expandRef
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'expand is False for function pointers'
|
||||
expand = ' &'
|
||||
if not self.expand:
|
||||
expand = ''
|
||||
return Type.FullName(self) + expand
|
||||
|
||||
|
||||
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, expandPointer=False):
|
||||
Type.__init__(self, name, const, default)
|
||||
self.expand = expandPointer
|
||||
|
||||
|
||||
def FullName(self):
|
||||
'expand is False for function pointer'
|
||||
expand = ' *'
|
||||
if not self.expand:
|
||||
expand = ''
|
||||
return Type.FullName(self) + expand
|
||||
|
||||
|
||||
|
||||
class FundamentalType(Type):
|
||||
'One of the fundamental types (int, void...).'
|
||||
|
||||
def __init__(self, name, const=False):
|
||||
Type.__init__(self, name, const)
|
||||
|
||||
|
||||
|
||||
class FunctionType(Type):
|
||||
'A pointer to a function.'
|
||||
|
||||
def __init__(self, result, params):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
self.parameters = params
|
||||
self.name = self.FullName()
|
||||
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (*)' % self.result.FullName()
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
|
||||
class MethodType(FunctionType):
|
||||
'A pointer to a member function of a class.'
|
||||
|
||||
def __init__(self, result, params, class_):
|
||||
Type.__init__(self, '', False)
|
||||
self.result = result
|
||||
self.parameters = params
|
||||
self.class_ = class_
|
||||
self.name = self.FullName()
|
||||
|
||||
def FullName(self):
|
||||
full = '%s (%s::*)' % (self.result.FullName(), self.class_)
|
||||
params = [x.FullName() for x in self.parameters]
|
||||
full += '(%s)' % ', '.join(params)
|
||||
return full
|
||||
|
||||
|
||||
|
||||
class Variable(Declaration):
|
||||
'Represents a global variable.'
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
# instance of Type
|
||||
self.type = type
|
||||
|
||||
|
||||
|
||||
class ClassVariable(Variable):
|
||||
'Represents a class variable.'
|
||||
|
||||
def __init__(self, type, name, class_, visib, static):
|
||||
Variable.__init__(self, type, name, None)
|
||||
self.visibility = visib
|
||||
self.static = static
|
||||
self.class_ = class_
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::' + self.name
|
||||
|
||||
|
||||
|
||||
class Enumeration(Declaration):
|
||||
|
||||
def __init__(self, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.values = {} # dict of str => int
|
||||
|
||||
def ValueFullName(self, name):
|
||||
assert name in self.values
|
||||
namespace = self.namespace
|
||||
if namespace:
|
||||
namespace += '::'
|
||||
return namespace + name
|
||||
|
||||
|
||||
|
||||
class ClassEnumeration(Enumeration):
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Enumeration.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
|
||||
def FullName(self):
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
def ValueFullName(self, name):
|
||||
assert name in self.values
|
||||
return '%s::%s' % (self.class_, name)
|
||||
|
||||
|
||||
|
||||
class Typedef(Declaration):
|
||||
|
||||
def __init__(self, type, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
self.type = type
|
||||
self.visibility = Scope.public
|
||||
|
||||
|
||||
class Union(Declaration):
|
||||
'Shallow declaration, because Unions are not supported yet'
|
||||
def __init__(self, name, namespace):
|
||||
Declaration.__init__(self, name, namespace)
|
||||
|
||||
|
||||
class ClassUnion(Union):
|
||||
|
||||
def __init__(self, name, class_, visib):
|
||||
Union.__init__(self, name, None)
|
||||
self.class_ = class_
|
||||
self.visibility = visib
|
||||
|
||||
def FullName(self):
|
||||
return '%s::%s' % (self.class_, self.name)
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from __future__ import generators
|
||||
|
||||
def enumerate(seq):
|
||||
i = 0
|
||||
for x in seq:
|
||||
yield i, x
|
||||
i += 1
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
# a list of Exporter instances
|
||||
exporters = []
|
||||
@@ -1,26 +0,0 @@
|
||||
'''
|
||||
Various helpers for interface files.
|
||||
'''
|
||||
|
||||
from settings import *
|
||||
|
||||
#==============================================================================
|
||||
# FunctionWrapper
|
||||
#==============================================================================
|
||||
class FunctionWrapper(object):
|
||||
'''Holds information about a wrapper for a function or a method. It is in 2
|
||||
parts: the name of the Wrapper, and its code. The code is placed in the
|
||||
declaration section of the module, while the name is used to def' the
|
||||
function or method (with the pyste namespace prepend to it). If code is None,
|
||||
the name is left unchanged.
|
||||
'''
|
||||
|
||||
def __init__(self, name, code=None):
|
||||
self.name = name
|
||||
self.code = code
|
||||
|
||||
def FullName(self):
|
||||
if self.code:
|
||||
return namespaces.pyste + self.name
|
||||
else:
|
||||
return self.name
|
||||
@@ -1,187 +0,0 @@
|
||||
import os.path
|
||||
import copy
|
||||
import exporters
|
||||
from ClassExporter import ClassExporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from IncludeExporter import IncludeExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
from exporterutils import FunctionWrapper
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# DeclarationInfo
|
||||
#==============================================================================
|
||||
class DeclarationInfo:
|
||||
|
||||
def __init__(self, otherInfo=None):
|
||||
self.__infos = {}
|
||||
self.__attributes = {}
|
||||
if otherInfo is not None:
|
||||
self.__infos = copy.deepcopy(otherInfo.__infos)
|
||||
self.__attributes = copy.deepcopy(otherInfo.__attributes)
|
||||
|
||||
|
||||
def __getitem__(self, name):
|
||||
'Used to access sub-infos'
|
||||
if name.startswith('__'):
|
||||
raise AttributeError
|
||||
default = DeclarationInfo()
|
||||
default._Attribute('name', name)
|
||||
return self.__infos.setdefault(name, default)
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self[name]
|
||||
|
||||
|
||||
def _Attribute(self, name, value=None):
|
||||
if value is None:
|
||||
# get value
|
||||
return self.__attributes.get(name)
|
||||
else:
|
||||
# set value
|
||||
self.__attributes[name] = value
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionInfo
|
||||
#==============================================================================
|
||||
class FunctionInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, tail=None, otherOption=None):
|
||||
DeclarationInfo.__init__(self, otherOption)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
# create a FunctionExporter
|
||||
exporter = FunctionExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassInfo
|
||||
#==============================================================================
|
||||
class ClassInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include, tail=None, otherInfo=None):
|
||||
DeclarationInfo.__init__(self, otherInfo)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
# create a ClassExporter
|
||||
exporter = ClassExporter(InfoWrapper(self), tail)
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# IncludeInfo
|
||||
#==============================================================================
|
||||
class IncludeInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, include):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = IncludeExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# templates
|
||||
#==============================================================================
|
||||
def GenerateName(name, type_list):
|
||||
name = name.replace('::', '_')
|
||||
names = [name] + type_list
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
class ClassTemplateInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
|
||||
|
||||
def Instantiate(self, type_list, rename=None):
|
||||
if not rename:
|
||||
rename = GenerateName(self._Attribute('name'), type_list)
|
||||
# generate code to instantiate the template
|
||||
types = ', '.join(type_list)
|
||||
tail = 'typedef %s< %s > %s;\n' % (self._Attribute('name'), types, rename)
|
||||
tail += 'void __instantiate_%s()\n' % rename
|
||||
tail += '{ sizeof(%s); }\n\n' % rename
|
||||
# create a ClassInfo
|
||||
class_ = ClassInfo(rename, self._Attribute('include'), tail, self)
|
||||
return class_
|
||||
|
||||
|
||||
def __call__(self, types, rename=None):
|
||||
if isinstance(types, str):
|
||||
types = types.split()
|
||||
return self.Instantiate(types, rename)
|
||||
|
||||
#==============================================================================
|
||||
# EnumInfo
|
||||
#==============================================================================
|
||||
class EnumInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, name, include):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('name', name)
|
||||
self._Attribute('include', include)
|
||||
exporter = EnumExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# HeaderInfo
|
||||
#==============================================================================
|
||||
class HeaderInfo(DeclarationInfo):
|
||||
|
||||
def __init__(self, include):
|
||||
DeclarationInfo.__init__(self)
|
||||
self._Attribute('include', include)
|
||||
exporter = HeaderExporter(InfoWrapper(self))
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# InfoWrapper
|
||||
#==============================================================================
|
||||
class InfoWrapper:
|
||||
'Provides a nicer interface for a info'
|
||||
|
||||
def __init__(self, info):
|
||||
self.__dict__['_info'] = info # so __setattr__ is not called
|
||||
|
||||
def __getitem__(self, name):
|
||||
return InfoWrapper(self._info[name])
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._info._Attribute(name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
self._info._Attribute(name, value)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Functions
|
||||
#==============================================================================
|
||||
def exclude(option):
|
||||
option._Attribute('exclude', True)
|
||||
|
||||
def set_policy(option, policy):
|
||||
option._Attribute('policy', policy)
|
||||
|
||||
def rename(option, name):
|
||||
option._Attribute('rename', name)
|
||||
|
||||
def set_wrapper(option, wrapper):
|
||||
if isinstance(wrapper, str):
|
||||
wrapper = FunctionWrapper(wrapper)
|
||||
option._Attribute('wrapper', wrapper)
|
||||
|
||||
def instantiate(template, types, rename=None):
|
||||
if isinstance(types, str):
|
||||
types = types.split()
|
||||
return template.Instantiate(types, rename)
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
|
||||
|
||||
class Policy:
|
||||
'Represents one of the call policies of boost.python.'
|
||||
|
||||
def __init__(self):
|
||||
raise RuntimeError, "Can't create an instance of the class Policy"
|
||||
|
||||
|
||||
def Code(self):
|
||||
'Returns the string corresponding to a instancialization of the policy.'
|
||||
pass
|
||||
|
||||
|
||||
def _next(self):
|
||||
if self.next is not None:
|
||||
return ', %s >' % self.next.Code()
|
||||
else:
|
||||
return ' >'
|
||||
|
||||
|
||||
|
||||
class return_internal_reference(Policy):
|
||||
'Ties the return value to one of the parameters.'
|
||||
|
||||
def __init__(self, param=1, next=None):
|
||||
'''
|
||||
param is the position of the parameter, or None for "self".
|
||||
next indicates the next policy, or None.
|
||||
'''
|
||||
self.param = param
|
||||
self.next=next
|
||||
|
||||
|
||||
def Code(self):
|
||||
c = 'return_internal_reference< %i' % self.param
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
|
||||
|
||||
class with_custodian_and_ward(Policy):
|
||||
'Ties lifetime of two arguments of a function.'
|
||||
|
||||
def __init__(self, custodian, ward, next=None):
|
||||
self.custodian = custodian
|
||||
self.ward = ward
|
||||
self.next = next
|
||||
|
||||
def Code(self):
|
||||
c = 'with_custodian_and_ward< %i, %i' % (self.custodian, self.ward)
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
|
||||
|
||||
class return_value_policy(Policy):
|
||||
'Policy to convert return values.'
|
||||
|
||||
def __init__(self, which, next=None):
|
||||
self.which = which
|
||||
self.next = next
|
||||
|
||||
|
||||
def Code(self):
|
||||
c = 'return_value_policy< %s' % self.which
|
||||
c += self._next()
|
||||
return c
|
||||
|
||||
|
||||
# values for return_value_policy
|
||||
reference_existing_object = 'reference_existing_object'
|
||||
copy_const_reference = 'copy_const_reference'
|
||||
copy_non_const_reference = 'copy_non_const_reference'
|
||||
manage_new_object = 'manage_new_object'
|
||||
@@ -1,17 +0,0 @@
|
||||
import profile
|
||||
import pstats
|
||||
import pyste
|
||||
|
||||
import psyco
|
||||
import elementtree.XMLTreeBuilder as XMLTreeBuilder
|
||||
import GCCXMLParser
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#psyco.bind(XMLTreeBuilder.fixtext)
|
||||
#psyco.bind(XMLTreeBuilder.fixname)
|
||||
#psyco.bind(XMLTreeBuilder.TreeBuilder)
|
||||
#psyco.bind(GCCXMLParser.GCCXMLParser)
|
||||
profile.run('pyste.Main()', 'profile')
|
||||
p = pstats.Stats('profile')
|
||||
p.strip_dirs().sort_stats(-1).print_stats()
|
||||
@@ -1,154 +0,0 @@
|
||||
'''
|
||||
Usage:
|
||||
pyste [options] --module=<name> interface-files
|
||||
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is "pyste"
|
||||
'''
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import exporters
|
||||
import CodeUnit
|
||||
import infos
|
||||
import exporterutils
|
||||
import settings
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
from Exporter import Exporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from ClassExporter import ClassExporter
|
||||
from IncludeExporter import IncludeExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
|
||||
|
||||
def GetDefaultIncludes():
|
||||
if 'INCLUDE' in os.environ:
|
||||
include = os.environ['INCLUDE']
|
||||
return include.split(os.pathsep)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__
|
||||
sys.exit(1)
|
||||
|
||||
options, files = getopt.getopt(sys.argv[1:], 'I:D:', ['module=', 'out=', 'no-using', 'pyste-ns=', 'debug'])
|
||||
includes = GetDefaultIncludes()
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
elif opt == '-D':
|
||||
defines.append(value)
|
||||
elif opt == '--module':
|
||||
module = value
|
||||
elif opt == '--out':
|
||||
out = value
|
||||
elif opt == '--no-using':
|
||||
settings.namespaces.python = 'boost::python::'
|
||||
CodeUnit.CodeUnit.USING_BOOST_NS = False
|
||||
elif opt == '--pyste-ns':
|
||||
settings.namespaces.pyste = value + '::'
|
||||
elif opt == '--debug':
|
||||
settings.DEBUG = True
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
|
||||
if not files or not module:
|
||||
Usage()
|
||||
if not out:
|
||||
out = module + '.cpp'
|
||||
return includes, defines, module, out, files
|
||||
|
||||
|
||||
def CreateContext():
|
||||
'create the context where a interface file can be executed'
|
||||
context = {}
|
||||
# infos
|
||||
context['Function'] = infos.FunctionInfo
|
||||
context['Class'] = infos.ClassInfo
|
||||
context['Include'] = infos.IncludeInfo
|
||||
context['Template'] = infos.ClassTemplateInfo
|
||||
context['Enum'] = infos.EnumInfo
|
||||
context['AllFromHeader'] = infos.HeaderInfo
|
||||
# functions
|
||||
context['rename'] = infos.rename
|
||||
context['set_policy'] = infos.set_policy
|
||||
context['exclude'] = infos.exclude
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
context['return_value_policy'] = return_value_policy
|
||||
context['reference_existing_object'] = reference_existing_object
|
||||
context['copy_const_reference'] = copy_const_reference
|
||||
context['copy_non_const_reference'] = copy_non_const_reference
|
||||
context['manage_new_object'] = manage_new_object
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
return context
|
||||
|
||||
|
||||
def Main():
|
||||
includes, defines, module, out, interfaces = ParseArguments()
|
||||
# execute the interface files
|
||||
for interface in interfaces:
|
||||
context = CreateContext()
|
||||
execfile(interface, context)
|
||||
# parse all the C++ code
|
||||
parser = CppParser(includes, defines)
|
||||
exports = exporters.exporters[:]
|
||||
for export in exports:
|
||||
try:
|
||||
export.Parse(parser)
|
||||
except CppParserError, e:
|
||||
print '\n'
|
||||
print '***', e, ': exitting'
|
||||
return 2
|
||||
print
|
||||
# sort the exporters by its order
|
||||
exports = [(x.Order(), x) for x in exporters.exporters]
|
||||
exports.sort()
|
||||
exports = [x for _, x in exports]
|
||||
# now generate the wrapper code
|
||||
codeunit = CodeUnit.CodeUnit(module)
|
||||
exported_names = []
|
||||
for export in exports:
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
exported_names.append(export.Name())
|
||||
codeunit.Save(out)
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if it is installed'
|
||||
try:
|
||||
import psyco
|
||||
import elementtree.XMLTreeBuilder as XMLTreeBuilder
|
||||
import GCCXMLParser
|
||||
|
||||
psyco.bind(XMLTreeBuilder.fixtext)
|
||||
psyco.bind(XMLTreeBuilder.fixname)
|
||||
psyco.bind(XMLTreeBuilder.TreeBuilder)
|
||||
psyco.bind(GCCXMLParser.GCCXMLParser)
|
||||
except ImportError: pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
UsePsyco()
|
||||
status = Main()
|
||||
sys.exit(status)
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
#==============================================================================
|
||||
# Global information
|
||||
#==============================================================================
|
||||
|
||||
DEBUG = False
|
||||
|
||||
class namespaces:
|
||||
boost = 'boost::'
|
||||
pyste = ''
|
||||
python = '' # default is to not use boost::python namespace explicitly, so
|
||||
# use the "using namespace" statement instead
|
||||
@@ -1,19 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set MODULE_NAME=%1
|
||||
set PYSTE_FILE=%2
|
||||
set BOOST_ROOT=d:/programming/libraries/boost-cvs
|
||||
set PYTHON_ROOT=c:/python
|
||||
set STLPORT_ROOT=d:/programming/libraries/stlport-4.5.3
|
||||
set PYSTE_FILE_DIR=%@PATH[%PYSTE_FILE]
|
||||
|
||||
python ../src/pyste.py -I%PYSTE_FILE_DIR --out=%MODULE_NAME.cpp --module=%MODULE_NAME %PYSTE_FILE
|
||||
|
||||
icl /nologo /LD /GR /GX -I%PYSTE_FILE_DIR -I%STLPORT_ROOT/stlport -I%BOOST_ROOT/boost -I%PYTHON_ROOT/include %MODULE_NAME.cpp /link /libpath:%PYTHON_ROOT/libs /libpath:%BOOST_ROOT/lib /libpath:%STLPORT_ROOT/lib boost_python.lib
|
||||
|
||||
rm %MODULE_NAME.cpp
|
||||
rm %MODULE_NAME.exp
|
||||
rm %MODULE_NAME.lib
|
||||
rm %MODULE_NAME.obj
|
||||
|
||||
endlocal
|
||||
@@ -1,27 +0,0 @@
|
||||
import unittest
|
||||
import os
|
||||
|
||||
class BasicExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
from basic import C, call_f
|
||||
|
||||
class D(C):
|
||||
def f(self, x=10):
|
||||
return x+1
|
||||
|
||||
d = D()
|
||||
c = C()
|
||||
|
||||
self.assertEqual(c.f(), 20)
|
||||
self.assertEqual(c.f(3), 6)
|
||||
self.assertEqual(d.f(), 11)
|
||||
self.assertEqual(d.f(3), 4)
|
||||
self.assertEqual(call_f(c), 20)
|
||||
self.assertEqual(call_f(c, 4), 8)
|
||||
self.assertEqual(call_f(d), 11)
|
||||
self.assertEqual(call_f(d, 3), 4)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,18 +0,0 @@
|
||||
import unittest
|
||||
from enums import *
|
||||
|
||||
class EnumsTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(int(color.Red), 0)
|
||||
self.assertEqual(int(color.Blue), 1)
|
||||
|
||||
self.assertEqual(int(X.Choices.Good), 1)
|
||||
self.assertEqual(int(X.Choices.Bad), 2)
|
||||
x = X()
|
||||
self.assertEqual(x.set(x.Choices.Good), 1)
|
||||
self.assertEqual(x.set(x.Choices.Bad), 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,15 +0,0 @@
|
||||
import unittest
|
||||
from header_test import *
|
||||
|
||||
class HeaderTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(choice.red, 0)
|
||||
self.assertEqual(choice.blue, 1)
|
||||
self.assertEqual(choice_str(choice.blue), 'blue')
|
||||
self.assertEqual(choice_str(choice.red), 'red')
|
||||
c = C()
|
||||
c.c = choice.blue
|
||||
self.assertEqual(c.get(), 'blue')
|
||||
c.c = choice.red
|
||||
self.assertEqual(c.get(), 'red')
|
||||
@@ -1,15 +0,0 @@
|
||||
import unittest
|
||||
from nested import *
|
||||
|
||||
class NestedTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(Root.staticXValue, 10)
|
||||
self.assertEqual(Root.Y.staticYValue, 20)
|
||||
z = Root.Y.Z()
|
||||
z.valueZ = 3
|
||||
self.assertEqual(z.valueZ, 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,25 +0,0 @@
|
||||
import unittest
|
||||
from operators import *
|
||||
|
||||
class OperatorTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
c = C()
|
||||
c.value = 3.0
|
||||
d = C()
|
||||
d.value = 2.0
|
||||
self.assertEqual(c.x, 10)
|
||||
self.assertEqual(C.x, 10)
|
||||
self.assertEqual(C.x, 10)
|
||||
self.assertEqual((c * d).value, 6.0)
|
||||
self.assertEqual((c + d).value, 5.0)
|
||||
self.assertEqual(int(c), 3)
|
||||
self.assertEqual(int(d), 2)
|
||||
self.assertEqual(c(), 10)
|
||||
self.assertEqual(d(), 10)
|
||||
self.assertEqual(c(3.0), 13.0)
|
||||
self.assertEqual(d(6.0), 16.0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,26 +0,0 @@
|
||||
import unittest
|
||||
from templates import *
|
||||
|
||||
class TemplatesTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
fp = FPoint()
|
||||
fp.i = 3.0
|
||||
fp.j = 4
|
||||
ip = IPoint()
|
||||
ip.x = 10
|
||||
ip.y = 3.0
|
||||
|
||||
self.assertEqual(fp.i, 3.0)
|
||||
self.assertEqual(fp.j, 4)
|
||||
self.assertEqual(ip.x, 10)
|
||||
self.assertEqual(ip.y, 3.0)
|
||||
self.assertEqual(type(fp.i), float)
|
||||
self.assertEqual(type(fp.j), int)
|
||||
self.assertEqual(type(ip.x), int)
|
||||
self.assertEqual(type(ip.y), float)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,31 +0,0 @@
|
||||
import unittest
|
||||
from virtual import *
|
||||
|
||||
class VirtualTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
|
||||
class D(C):
|
||||
def f_abs(self):
|
||||
return 3
|
||||
|
||||
class E(C):
|
||||
def f(self):
|
||||
return 10
|
||||
def name(self):
|
||||
return 'E'
|
||||
|
||||
d = D()
|
||||
e = E()
|
||||
|
||||
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.get_name(), 'E')
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,11 +0,0 @@
|
||||
import unittest
|
||||
from wrappertest import *
|
||||
|
||||
class WrapperTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
self.assertEqual(Range(10), range(10))
|
||||
self.assertEqual(C().Mul(10), [x*10 for x in range(10)])
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,20 +0,0 @@
|
||||
@echo off
|
||||
call build_pyste_nt basic ../example/basic.pyste
|
||||
call build_pyste_nt enums ../example/enums.pyste
|
||||
call build_pyste_nt header_test ../example/header_test.pyste
|
||||
call build_pyste_nt nested ../example/nested.pyste
|
||||
call build_pyste_nt operators ../example/operators.pyste
|
||||
call build_pyste_nt templates ../example/templates.pyste
|
||||
call build_pyste_nt virtual ../example/virtual.pyste
|
||||
call build_pyste_nt wrappertest ../example/wrappertest.pyste
|
||||
call build_pyste_nt unions ../example/unions.pyste
|
||||
|
||||
|
||||
runtests.py
|
||||
|
||||
if errorlevel != 0 goto end
|
||||
|
||||
rm *.dll
|
||||
rm *.pyc
|
||||
|
||||
:end
|
||||
Reference in New Issue
Block a user