Python prototype

release/4.3a0
dellaert 2014-11-14 17:47:25 +01:00
parent e07402a58a
commit 6c24fc2aca
11 changed files with 139 additions and 36 deletions

View File

@ -583,4 +583,16 @@ string Class::getSerializationExport() const {
return "BOOST_CLASS_EXPORT_GUID(" + qualifiedName("::") + ", \"" return "BOOST_CLASS_EXPORT_GUID(" + qualifiedName("::") + ", \""
+ qualifiedName() + "\");"; + qualifiedName() + "\");";
} }
/* ************************************************************************* */
void Class::python_wrapper(FileWriter& wrapperFile) const {
wrapperFile.oss << "class_<" << name << ">(\"" << name << "\")\n";
constructor.python_wrapper(wrapperFile, name);
BOOST_FOREACH(const StaticMethod& m, static_methods | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name);
BOOST_FOREACH(const Method& m, methods | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name);
wrapperFile.oss << ";\n\n";
}
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -111,6 +111,9 @@ public:
void deserialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, void deserialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile,
Str wrapperName, std::vector<std::string>& functionNames) const; Str wrapperName, std::vector<std::string>& functionNames) const;
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile) const;
friend std::ostream& operator<<(std::ostream& os, const Class& cls) { friend std::ostream& operator<<(std::ostream& os, const Class& cls) {
os << "class " << cls.name << "{\n"; os << "class " << cls.name << "{\n";
os << cls.constructor << ";\n"; os << cls.constructor << ";\n";

View File

@ -29,52 +29,55 @@
using namespace std; using namespace std;
using namespace wrap; using namespace wrap;
/* ************************************************************************* */ /* ************************************************************************* */
string Constructor::matlab_wrapper_name(const string& className) const { string Constructor::matlab_wrapper_name(Str className) const {
string str = "new_" + className; string str = "new_" + className;
return str; return str;
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperName, void Constructor::proxy_fragment(FileWriter& file,
bool hasParent, const int id, const ArgumentList args) const { const std::string& wrapperName, bool hasParent, const int id,
const ArgumentList args) const {
size_t nrArgs = args.size(); size_t nrArgs = args.size();
// check for number of arguments... // check for number of arguments...
file.oss << " elseif nargin == " << nrArgs; file.oss << " elseif nargin == " << nrArgs;
if (nrArgs>0) file.oss << " && "; if (nrArgs > 0)
file.oss << " && ";
// ...and their types // ...and their types
bool first = true; bool first = true;
for(size_t i=0;i<nrArgs;i++) { for (size_t i = 0; i < nrArgs; i++) {
if (!first) file.oss << " && "; if (!first)
file.oss << "isa(varargin{" << i+1 << "},'" << args[i].matlabClass(".") << "')"; file.oss << " && ";
first=false; file.oss << "isa(varargin{" << i + 1 << "},'" << args[i].matlabClass(".")
<< "')";
first = false;
} }
// emit code for calling constructor // emit code for calling constructor
if(hasParent) if (hasParent)
file.oss << "\n [ my_ptr, base_ptr ] = "; file.oss << "\n [ my_ptr, base_ptr ] = ";
else else
file.oss << "\n my_ptr = "; file.oss << "\n my_ptr = ";
file.oss << wrapperName << "(" << id; file.oss << wrapperName << "(" << id;
// emit constructor arguments // emit constructor arguments
for(size_t i=0;i<nrArgs;i++) { for (size_t i = 0; i < nrArgs; i++) {
file.oss << ", "; file.oss << ", ";
file.oss << "varargin{" << i+1 << "}"; file.oss << "varargin{" << i + 1 << "}";
} }
file.oss << ");\n"; file.oss << ");\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */
string Constructor::wrapper_fragment(FileWriter& file, string Constructor::wrapper_fragment(FileWriter& file, Str cppClassName,
const string& cppClassName, Str matlabUniqueName, Str cppBaseClassName, int id,
const string& matlabUniqueName, const ArgumentList& al) const {
const string& cppBaseClassName,
int id,
const ArgumentList& al) const {
const string wrapFunctionName = matlabUniqueName + "_constructor_" + boost::lexical_cast<string>(id); const string wrapFunctionName = matlabUniqueName + "_constructor_"
+ boost::lexical_cast<string>(id);
file.oss << "void " << wrapFunctionName << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])" << endl; file.oss << "void " << wrapFunctionName
<< "(int nargout, mxArray *out[], int nargin, const mxArray *in[])"
<< endl;
file.oss << "{\n"; file.oss << "{\n";
file.oss << " mexAtExit(&_deleteAllObjects);\n"; file.oss << " mexAtExit(&_deleteAllObjects);\n";
//Typedef boost::shared_ptr //Typedef boost::shared_ptr
@ -82,22 +85,29 @@ string Constructor::wrapper_fragment(FileWriter& file,
file.oss << "\n"; file.oss << "\n";
//Check to see if there will be any arguments and remove {} for consiseness //Check to see if there will be any arguments and remove {} for consiseness
if(al.size() > 0) if (al.size() > 0)
al.matlab_unwrap(file); // unwrap arguments al.matlab_unwrap(file); // unwrap arguments
file.oss << " Shared *self = new Shared(new " << cppClassName << "(" << al.names() << "));" << endl; file.oss << " Shared *self = new Shared(new " << cppClassName << "("
<< al.names() << "));" << endl;
file.oss << " collector_" << matlabUniqueName << ".insert(self);\n"; file.oss << " collector_" << matlabUniqueName << ".insert(self);\n";
if(verbose_) if (verbose_)
file.oss << " std::cout << \"constructed \" << self << std::endl;" << endl; file.oss << " std::cout << \"constructed \" << self << std::endl;" << endl;
file.oss << " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);" << endl; file.oss
file.oss << " *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;" << endl; << " out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);"
<< endl;
file.oss << " *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;"
<< endl;
// If we have a base class, return the base class pointer (MATLAB will call the base class collectorInsertAndMakeBase to add this to the collector and recurse the heirarchy) // If we have a base class, return the base class pointer (MATLAB will call the base class collectorInsertAndMakeBase to add this to the collector and recurse the heirarchy)
if(!cppBaseClassName.empty()) { if (!cppBaseClassName.empty()) {
file.oss << "\n"; file.oss << "\n";
file.oss << " typedef boost::shared_ptr<" << cppBaseClassName << "> SharedBase;\n"; file.oss << " typedef boost::shared_ptr<" << cppBaseClassName
file.oss << " out[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);\n"; << "> SharedBase;\n";
file.oss << " *reinterpret_cast<SharedBase**>(mxGetData(out[1])) = new SharedBase(*self);\n"; file.oss
<< " out[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);\n";
file.oss
<< " *reinterpret_cast<SharedBase**>(mxGetData(out[1])) = new SharedBase(*self);\n";
} }
file.oss << "}" << endl; file.oss << "}" << endl;
@ -106,3 +116,9 @@ string Constructor::wrapper_fragment(FileWriter& file,
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Constructor::python_wrapper(FileWriter& wrapperFile, Str className) const {
wrapperFile.oss << " .def(\"" << name_ << "\", &" << className << "::" << name_
<< ");\n";
}
/* ************************************************************************* */

View File

@ -28,6 +28,8 @@ namespace wrap {
// Constructor class // Constructor class
struct Constructor: public OverloadedFunction { struct Constructor: public OverloadedFunction {
typedef const std::string& Str;
/// Constructor creates an empty class /// Constructor creates an empty class
Constructor(bool verbose = false) { Constructor(bool verbose = false) {
verbose_ = verbose; verbose_ = verbose;
@ -45,7 +47,7 @@ struct Constructor: public OverloadedFunction {
// classFile is class proxy file, e.g., ../matlab/@Point2/Point2.m // classFile is class proxy file, e.g., ../matlab/@Point2/Point2.m
/// wrapper name /// wrapper name
std::string matlab_wrapper_name(const std::string& className) const; std::string matlab_wrapper_name(Str className) const;
void comment_fragment(FileWriter& proxyFile) const { void comment_fragment(FileWriter& proxyFile) const {
if (nrOverloads() > 0) if (nrOverloads() > 0)
@ -61,19 +63,21 @@ struct Constructor: public OverloadedFunction {
* Create fragment to select constructor in proxy class, e.g., * Create fragment to select constructor in proxy class, e.g.,
* if nargin == 2, obj.self = new_Pose3_RP(varargin{1},varargin{2}); end * if nargin == 2, obj.self = new_Pose3_RP(varargin{1},varargin{2}); end
*/ */
void proxy_fragment(FileWriter& file, const std::string& wrapperName, void proxy_fragment(FileWriter& file, Str wrapperName, bool hasParent,
bool hasParent, const int id, const ArgumentList args) const; const int id, const ArgumentList args) const;
/// cpp wrapper /// cpp wrapper
std::string wrapper_fragment(FileWriter& file, std::string wrapper_fragment(FileWriter& file, Str cppClassName,
const std::string& cppClassName, const std::string& matlabUniqueName, Str matlabUniqueName, Str cppBaseClassName, int id,
const std::string& cppBaseClassName, int id,
const ArgumentList& al) const; const ArgumentList& al) const;
/// constructor function /// constructor function
void generate_construct(FileWriter& file, const std::string& cppClassName, void generate_construct(FileWriter& file, Str cppClassName,
std::vector<ArgumentList>& args_list) const; std::vector<ArgumentList>& args_list) const;
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile, Str className) const;
friend std::ostream& operator<<(std::ostream& os, const Constructor& m) { friend std::ostream& operator<<(std::ostream& os, const Constructor& m) {
for (size_t i = 0; i < m.nrOverloads(); i++) for (size_t i = 0; i < m.nrOverloads(); i++)
os << m.name_ << m.argLists_[i]; os << m.name_ << m.argLists_[i];

View File

@ -127,6 +127,11 @@ void GlobalFunction::generateSingleFunction(const string& toolboxPath,
mfunctionFile.emit(true); mfunctionFile.emit(true);
} }
/* ************************************************************************* */
void GlobalFunction::python_wrapper(FileWriter& wrapperFile) const {
wrapperFile.oss << "def(\"" << name_ << "\", " << name_ << ");\n";
}
/* ************************************************************************* */ /* ************************************************************************* */
} // \namespace wrap } // \namespace wrap

View File

@ -35,6 +35,9 @@ struct GlobalFunction: public FullyOverloadedFunction {
const std::string& wrapperName, const TypeAttributesTable& typeAttributes, const std::string& wrapperName, const TypeAttributesTable& typeAttributes,
FileWriter& file, std::vector<std::string>& functionNames) const; FileWriter& file, std::vector<std::string>& functionNames) const;
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile) const;
private: private:
// Creates a single global function - all in same namespace // Creates a single global function - all in same namespace

View File

@ -650,3 +650,31 @@ void Module::WriteRTTIRegistry(FileWriter& wrapperFile, const std::string& modul
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Module::python_wrapper(const string& toolboxPath) const {
fs::create_directories(toolboxPath);
// create the unified .cpp switch file
const string wrapperName = name + "_python";
string wrapperFileName = toolboxPath + "/" + wrapperName + ".cpp";
FileWriter wrapperFile(wrapperFileName, verbose, "//");
wrapperFile.oss << "#include <boost/python.hpp>\n\n";
wrapperFile.oss << "using namespace boost::python;\n";
wrapperFile.oss << "BOOST_PYTHON_MODULE(" + name + ")\n";
wrapperFile.oss << "{\n";
// write out classes
BOOST_FOREACH(const Class& cls, expandedClasses)
cls.python_wrapper(wrapperFile);
// write out global functions
BOOST_FOREACH(const GlobalFunctions::value_type& p, global_functions)
p.second.python_wrapper(wrapperFile);
// finish wrapper file
wrapperFile.oss << "}\n";
wrapperFile.emit(true);
}
/* ************************************************************************* */

View File

@ -70,6 +70,9 @@ struct Module {
void finish_wrapper(FileWriter& file, void finish_wrapper(FileWriter& file,
const std::vector<std::string>& functionNames) const; const std::vector<std::string>& functionNames) const;
/// Python code generation:
void python_wrapper(const std::string& path) const;
private: private:
static std::vector<Class> ExpandTypedefInstantiations( static std::vector<Class> ExpandTypedefInstantiations(
const std::vector<Class>& classes, const std::vector<Class>& classes,

View File

@ -165,3 +165,10 @@ string StaticMethod::wrapper_call(FileWriter& wrapperFile, Str cppClassName,
} }
/* ************************************************************************* */ /* ************************************************************************* */
void StaticMethod::python_wrapper(FileWriter& wrapperFile,
Str className) const {
wrapperFile.oss << " .def(\"" << name_ << "\", &" << className << "::" << name_
<< ");\n";
}
/* ************************************************************************* */

View File

@ -52,6 +52,9 @@ struct StaticMethod: public FullyOverloadedFunction {
Str wrapperName, const TypeAttributesTable& typeAttributes, Str wrapperName, const TypeAttributesTable& typeAttributes,
std::vector<std::string>& functionNames) const; std::vector<std::string>& functionNames) const;
// emit python wrapper
void python_wrapper(FileWriter& wrapperFile, Str className) const;
friend std::ostream& operator<<(std::ostream& os, const StaticMethod& m) { friend std::ostream& operator<<(std::ostream& os, const StaticMethod& m) {
for (size_t i = 0; i < m.nrOverloads(); i++) for (size_t i = 0; i < m.nrOverloads(); i++)
os << "static " << m.returnVals_[i] << " " << m.name_ << m.argLists_[i]; os << "static " << m.returnVals_[i] << " " << m.name_ << m.argLists_[i];

View File

@ -460,6 +460,25 @@ TEST( wrap, matlab_code_geometry ) {
EXPECT(files_equal(epath + "overloadedGlobalFunction.m" , apath + "overloadedGlobalFunction.m" )); EXPECT(files_equal(epath + "overloadedGlobalFunction.m" , apath + "overloadedGlobalFunction.m" ));
} }
/* ************************************************************************* */
TEST( wrap, python_code_geometry ) {
// Parse into class object
string header_path = topdir + "/wrap/tests";
Module module(header_path,"geometry",enable_verbose);
string path = topdir + "/wrap";
// clean out previous generated code
fs::remove_all("actual-python");
// emit MATLAB code
// make_geometry will not compile, use make testwrap to generate real make
module.python_wrapper("actual-python");
string epath = path + "/tests/expected-python/";
string apath = "actual-python/";
EXPECT(files_equal(epath + "geometry_python.cpp", apath + "geometry_python.cpp" ));
}
/* ************************************************************************* */ /* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr); } int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
/* ************************************************************************* */ /* ************************************************************************* */