From 92a0cf67c90577bd141958bed2a9f04f2049b5c1 Mon Sep 17 00:00:00 2001 From: Alex Cunningham Date: Wed, 7 Dec 2011 03:05:37 +0000 Subject: [PATCH] Fixed ambiguity issues with returning non-ptr classes, added new copies of functions to gtsam.h and depreciated old ones --- gtsam.h | 96 ++++++++++++++++++++++------- wrap/Class.cpp | 4 +- wrap/Method.cpp | 2 +- wrap/Method.h | 2 - wrap/Module.cpp | 72 +++++++++++----------- wrap/Module.h | 4 +- wrap/ReturnValue.cpp | 36 +++++------ wrap/ReturnValue.h | 16 ++--- wrap/StaticMethod.cpp | 26 ++++---- wrap/StaticMethod.h | 12 ++-- wrap/geometry.h | 8 +++ wrap/tests/expected/@Test/Test.m | 1 + wrap/tests/expected/Makefile | 10 ++- wrap/tests/expected/make_geometry.m | 3 + wrap/tests/testSpirit.cpp | 34 ++++++++++ wrap/tests/testWrap.cpp | 24 ++++---- 16 files changed, 225 insertions(+), 125 deletions(-) diff --git a/gtsam.h b/gtsam.h index 6d59ffc22..b270a17ec 100644 --- a/gtsam.h +++ b/gtsam.h @@ -1,37 +1,61 @@ /** - * GTSAM Wrap Module definition + * GTSAM Wrap Module Definition * * These are the current classes available through the matlab toolbox interface, * add more functions/classes as they are available. * * Requirements: - * Constructors must appear in a class before any methods - * Methods can only return Matrix, Vector, double, int, void, and a shared_ptr to any other object - * Comments can use either C++ or C style + * Classes must start with an uppercase letter + * Only one Method/Constructor per line + * Methods can return + * - Eigen types: Matrix, Vector + * - C/C++ basic types: string, bool, size_t, int, double + * - void + * - Any class with which be copied with boost::make_shared() + * - boost::shared_ptr of any object type + * Arguments to functions any of + * - Eigen types: Matrix, Vector + * - Eigen types and classes as an optionally const reference + * - C/C++ basic types: string, bool, size_t, int, double + * - Any class with which be copied with boost::make_shared() (except Eigen) + * - boost::shared_ptr of any object type (except Eigen) + * Comments can use either C++ or C style, with multiple lines * Methods must start with a lowercase letter * Static methods must start with a letter (upper or lowercase) and use the "static" keyword - * Classes must start with an uppercase letter + */ + +/** + * Status: + * - Depreciated versions of functions that return a shared_ptr unnecessarily are still present + * - TODO: global functions + * - TODO: namespace detection to handle nested namespaces */ class Point2 { Point2(); Point2(double x, double y); - static Point2* Expmap_(Vector v); + static Point2 Expmap(Vector v); static Vector Logmap(const Point2& p); void print(string s) const; double x(); double y(); + Vector localCoordinates(const Point2& p); + Point2 compose(const Point2& p2); + Point2 between(const Point2& p2); + Point2 retract(Vector v); + + // Depreciated interface Point2* compose_(const Point2& p2); Point2* between_(const Point2& p2); - Vector localCoordinates(const Point2& p); Point2* retract_(Vector v); + static Point2* Expmap_(Vector v); }; class Point3 { Point3(); Point3(double x, double y, double z); Point3(Vector v); - static Point3* Expmap_(Vector v); + static Point3 Expmap(Vector v); static Vector Logmap(const Point3& p); void print(string s) const; bool equals(const Point3& p, double tol); @@ -39,31 +63,43 @@ class Point3 { double x(); double y(); double z(); + Vector localCoordinates(const Point3& p); + Point3 retract(Vector v); + Point3 compose(const Point3& p2); + Point3 between(const Point3& p2); + + // Depreciated interface + static Point3* Expmap_(Vector v); Point3* compose_(const Point3& p2); Point3* between_(const Point3& p2); - Vector localCoordinates(const Point3& p); Point3* retract_(Vector v); }; class Rot2 { Rot2(); Rot2(double theta); - static Rot2* Expmap_(Vector v); + static Rot2 Expmap(Vector v); static Vector Logmap(const Rot2& p); void print(string s) const; bool equals(const Rot2& rot, double tol) const; double c() const; double s() const; + Vector localCoordinates(const Rot2& p); + Rot2 retract(Vector v); + Rot2 compose(const Rot2& p2); + Rot2 between(const Rot2& p2); + + // Depreciated interface Rot2* compose_(const Rot2& p2); Rot2* between_(const Rot2& p2); - Vector localCoordinates(const Rot2& p); Rot2* retract_(Vector v); + static Rot2* Expmap_(Vector v); }; class Rot3 { Rot3(); Rot3(Matrix R); - static Rot3* Expmap_(Vector v); + static Rot3 Expmap(Vector v); static Vector Logmap(const Rot3& p); static Rot3 ypr(double y, double p, double r); Matrix matrix() const; @@ -72,10 +108,16 @@ class Rot3 { Vector ypr() const; void print(string s) const; bool equals(const Rot3& rot, double tol) const; + Vector localCoordinates(const Rot3& p); + Rot3 retract(Vector v); + Rot3 compose(const Rot3& p2); + Rot3 between(const Rot3& p2); + + // Depreciated interface Rot3* compose_(const Rot3& p2); Rot3* between_(const Rot3& p2); - Vector localCoordinates(const Rot3& p); Rot3* retract_(Vector v); + static Rot3* Expmap_(Vector v); }; class Pose2 { @@ -84,7 +126,7 @@ class Pose2 { Pose2(double theta, const Point2& t); Pose2(const Rot2& r, const Point2& t); Pose2(Vector v); - static Pose2* Expmap_(Vector v); + static Pose2 Expmap(Vector v); static Vector Logmap(const Pose2& p); void print(string s) const; bool equals(const Pose2& pose, double tol) const; @@ -92,10 +134,16 @@ class Pose2 { double y() const; double theta() const; int dim() const; + Vector localCoordinates(const Pose2& p); + Pose2 retract(Vector v); + Pose2 compose(const Pose2& p2); + Pose2 between(const Pose2& p2); + + // Depreciated interface Pose2* compose_(const Pose2& p2); Pose2* between_(const Pose2& p2); - Vector localCoordinates(const Pose2& p); Pose2* retract_(Vector v); + static Pose2* Expmap_(Vector v); }; class Pose3 { @@ -103,7 +151,7 @@ class Pose3 { Pose3(const Rot3& r, const Point3& t); Pose3(Vector v); Pose3(Matrix t); - static Pose3* Expmap_(Vector v); + static Pose3 Expmap(Vector v); static Vector Logmap(const Pose3& p); void print(string s) const; bool equals(const Pose3& pose, double tol) const; @@ -112,9 +160,16 @@ class Pose3 { double z() const; Matrix matrix() const; Matrix adjointMap() const; + Pose3 compose(const Pose3& p2); + Pose3 between(const Pose3& p2); + Pose3 retract(Vector v); + Point3 translation() const; + Rot3 rotation() const; + + // Depreciated interface + static Pose3* Expmap_(Vector v); Pose3* compose_(const Pose3& p2); Pose3* between_(const Pose3& p2); - Vector localCoordinates(const Pose3& p); Pose3* retract_(Vector v); Point3* translation_() const; Rot3* rotation_() const; @@ -259,17 +314,12 @@ class PlanarSLAMOdometry { class GaussianSequentialSolver { GaussianSequentialSolver(const GaussianFactorGraph& graph, bool useQR); GaussianBayesNet* eliminate() const; -// VectorValues* optimize() const; // FAIL: parse error here + VectorValues* optimize() const; // FAIL: parse error here GaussianFactor* marginalFactor(int j) const; Matrix marginalCovariance(int j) const; }; - - - - - //// These are considered to be broken and will be added back as they start working //// It's assumed that there have been interface changes that might break this // diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 489a56e18..cf56f73a1 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -86,7 +86,7 @@ void Class::matlab_make_fragment(ofstream& ofs, BOOST_FOREACH(Constructor c, constructors) ofs << mex << c.matlab_wrapper_name(name) << ".cpp" << endl; BOOST_FOREACH(StaticMethod sm, static_methods) - ofs << mex << name + "_" + sm.name_ << ".cpp" << endl; + ofs << mex << name + "_" + sm.name << ".cpp" << endl; ofs << endl << "cd @" << name << endl; BOOST_FOREACH(Method m, methods) ofs << mex << m.name_ << ".cpp" << endl; @@ -115,7 +115,7 @@ void Class::makefile_fragment(ofstream& ofs) { file_names.push_back(file_base); } BOOST_FOREACH(StaticMethod c, static_methods) { - string file_base = name + "_" + c.name_; + string file_base = name + "_" + c.name; file_names.push_back(file_base); } BOOST_FOREACH(Method c, methods) { diff --git a/wrap/Method.cpp b/wrap/Method.cpp index fbfce29a7..bf0426c3e 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -87,7 +87,7 @@ void Method::matlab_wrapper(const string& classPath, // call method // example: bool result = self->return_field(t); ofs << " "; - if (returnVal_.returns_!="void") + if (returnVal_.type1!="void") ofs << returnVal_.return_type(true,ReturnValue::pair) << " result = "; ofs << "self->" << name_ << "(" << args_.names() << ");\n"; diff --git a/wrap/Method.h b/wrap/Method.h index 9d3860ff1..843a2053b 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -39,8 +39,6 @@ struct Method { ArgumentList args_; ReturnValue returnVal_; -// std::string return_type(bool add_ptr, pairing p); - // MATLAB code generation // classPath is class directory, e.g., ../matlab/@Point2 diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 733e229ba..364e172ea 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -40,17 +40,17 @@ typedef rule Rule; /* ************************************************************************* */ Module::Module(const string& interfacePath, - const string& moduleName, bool verbose) : name(moduleName), verbose_(verbose) + const string& moduleName, bool enable_verbose) : name(moduleName), verbose(enable_verbose) { // these variables will be imperatively updated to gradually build [cls] // The one with postfix 0 are used to reset the variables after parse. ReturnValue retVal0, retVal; Argument arg0, arg; ArgumentList args0, args; - Constructor constructor0(verbose), constructor(verbose); - Method method0(verbose), method(verbose); - StaticMethod static_method0(verbose), static_method(verbose); - Class cls0(verbose),cls(verbose); + Constructor constructor0(enable_verbose), constructor(enable_verbose); + Method method0(enable_verbose), method(enable_verbose); + StaticMethod static_method0(enable_verbose), static_method(enable_verbose); + Class cls0(enable_verbose),cls(enable_verbose); //---------------------------------------------------------------------------- // Grammar with actions that build the Class object. Actions are @@ -68,7 +68,13 @@ Module::Module(const string& interfacePath, // lexeme_d turns off white space skipping // http://www.boost.org/doc/libs/1_37_0/libs/spirit/classic/doc/directives.html - Rule className_p = lexeme_d[upper_p >> *(alnum_p | '_')]; + Rule basisType_p = + (str_p("string") | "bool" | "size_t" | "int" | "double"); + + Rule eigenType_p = + (str_p("Vector") | "Matrix"); + + Rule className_p = lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - basisType_p; Rule classPtr_p = className_p [assign_a(arg.type)] >> @@ -79,21 +85,19 @@ Module::Module(const string& interfacePath, className_p [assign_a(arg.type)] >> ch_p('&') [assign_a(arg.is_ref,true)]; - Rule basisType_p = - (str_p("string") | "bool" | "size_t" | "int" | "double"); - - // FAIL: this will match against VectorValues in returntype - Rule eigenType_p = - (str_p("Vector") | "Matrix"); - - Rule argEigenType = + Rule argEigenType_p = eigenType_p[assign_a(arg.type)] >> !ch_p('*')[assign_a(arg.is_ptr,true)]; + Rule eigenRef_p = + !str_p("const") [assign_a(arg.is_const,true)] >> + eigenType_p [assign_a(arg.type)] >> + ch_p('&') [assign_a(arg.is_ref,true)]; + Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')]; Rule argument_p = - ((basisType_p[assign_a(arg.type)] | argEigenType | classPtr_p | classRef_p) >> name_p[assign_a(arg.name)]) + ((basisType_p[assign_a(arg.type)] | argEigenType_p | classRef_p | eigenRef_p | classPtr_p) >> name_p[assign_a(arg.name)]) [push_back_a(args, arg)] [assign_a(arg,arg0)]; @@ -107,22 +111,22 @@ Module::Module(const string& interfacePath, [assign_a(constructor,constructor0)]; Rule returnType1_p = - (basisType_p[assign_a(retVal.returns_)][assign_a(retVal.return1, ReturnValue::BASIS)]) | - (eigenType_p[assign_a(retVal.returns_)][assign_a(retVal.return1, ReturnValue::EIGEN)]) | - (className_p[assign_a(retVal.returns_)][assign_a(retVal.return1, ReturnValue::CLASS)]) >> - !ch_p('*') [assign_a(retVal.returns_ptr_,true)]; + (basisType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::BASIS)]) | + ((className_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::CLASS)]) >> + !ch_p('*')[assign_a(retVal.isPtr1,true)]) | + (eigenType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::EIGEN)]); Rule returnType2_p = - (basisType_p[assign_a(retVal.returns2_)][assign_a(retVal.return2, ReturnValue::BASIS)]) | - (eigenType_p[assign_a(retVal.returns2_)][assign_a(retVal.return2, ReturnValue::EIGEN)]) | - (className_p[assign_a(retVal.returns2_)][assign_a(retVal.return2, ReturnValue::CLASS)]) >> - !ch_p('*') [assign_a(retVal.returns_ptr2_,true)]; + (basisType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::BASIS)]) | + ((className_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::CLASS)]) >> + !ch_p('*') [assign_a(retVal.isPtr2,true)]) | + (eigenType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::EIGEN)]); Rule pair_p = (str_p("pair") >> '<' >> returnType1_p >> ',' >> returnType2_p >> '>') - [assign_a(retVal.returns_pair_,true)]; + [assign_a(retVal.isPair,true)]; - Rule void_p = str_p("void")[assign_a(retVal.returns_)]; + Rule void_p = str_p("void")[assign_a(retVal.type1)]; Rule returnType_p = void_p | returnType1_p | pair_p; @@ -142,23 +146,19 @@ Module::Module(const string& interfacePath, Rule staticMethodName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')]; Rule static_method_p = - (str_p("static") >> returnType_p >> staticMethodName_p[assign_a(static_method.name_)] >> + (str_p("static") >> returnType_p >> staticMethodName_p[assign_a(static_method.name)] >> '(' >> argumentList_p >> ')' >> ';' >> *comments_p) - [assign_a(static_method.args_,args)] + [assign_a(static_method.args,args)] [assign_a(args,args0)] - [assign_a(static_method.returnVal_,retVal)] + [assign_a(static_method.returnVal,retVal)] [assign_a(retVal,retVal0)] [push_back_a(cls.static_methods, static_method)] [assign_a(static_method,static_method0)]; - Rule methods_p = method_p | static_method_p; + Rule functions_p = constructor_p | method_p | static_method_p; Rule class_p = str_p("class") >> className_p[assign_a(cls.name)] >> '{' >> - *comments_p >> - *constructor_p >> - *comments_p >> - *methods_p >> - *comments_p >> + *(functions_p | comments_p) >> '}' >> ";"; Rule module_p = *comments_p >> +(class_p @@ -223,7 +223,7 @@ void Module::matlab_code(const string& toolboxPath, ofstream make_ofs(makeFile.c_str()); if(!make_ofs) throw CantOpenFile(makeFile); - if (verbose_) cerr << "generating " << matlabMakeFile << endl; + if (verbose) cerr << "generating " << matlabMakeFile << endl; emit_header_comment(ofs,"%"); ofs << "echo on" << endl << endl; ofs << "toolboxpath = mfilename('fullpath');" << endl; @@ -232,7 +232,7 @@ void Module::matlab_code(const string& toolboxPath, ofs << "clear delims" << endl; ofs << "addpath(toolboxpath);" << endl << endl; - if (verbose_) cerr << "generating " << makeFile << endl; + if (verbose) cerr << "generating " << makeFile << endl; emit_header_comment(make_ofs,"#"); make_ofs << "\nMEX = mex\n"; make_ofs << "MEXENDING = " << mexExt << "\n"; diff --git a/wrap/Module.h b/wrap/Module.h index a5aaad191..6ae9202cb 100644 --- a/wrap/Module.h +++ b/wrap/Module.h @@ -30,12 +30,12 @@ namespace wrap { struct Module { std::string name; ///< module name std::vector classes; ///< list of classes - bool verbose_; ///< verbose flag + bool verbose; ///< verbose flag /// constructor that parses interface file Module(const std::string& interfacePath, const std::string& moduleName, - bool verbose=true); + bool enable_verbose=true); /// MATLAB code generation: void matlab_code(const std::string& path, diff --git a/wrap/ReturnValue.cpp b/wrap/ReturnValue.cpp index e7b87e0fa..9d8606c5b 100644 --- a/wrap/ReturnValue.cpp +++ b/wrap/ReturnValue.cpp @@ -13,39 +13,39 @@ using namespace wrap; /* ************************************************************************* */ string ReturnValue::return_type(bool add_ptr, pairing p) { - if (p==pair && returns_pair_) { + if (p==pair && isPair) { string str = "pair< " + - wrap::maybe_shared_ptr(add_ptr && returns_ptr_, returns_) + ", " + - wrap::maybe_shared_ptr(add_ptr && returns_ptr2_, returns2_) + " >"; + wrap::maybe_shared_ptr(add_ptr && isPtr1, type1) + ", " + + wrap::maybe_shared_ptr(add_ptr && isPtr2, type2) + " >"; return str; } else - return wrap::maybe_shared_ptr(add_ptr && returns_ptr_, (p==arg2)? returns2_ : returns_); + return wrap::maybe_shared_ptr(add_ptr && isPtr1, (p==arg2)? type2 : type1); } /* ************************************************************************* */ void ReturnValue::wrap_result(std::ostream& ofs) { - if (returns_pair_) { + if (isPair) { // first return value in pair - if (returns_ptr_) // if we already have a pointer - ofs << " out[0] = wrap_shared_ptr(result.first,\"" << returns_ << "\");\n"; - else if (return1 == ReturnValue::CLASS) // if we are going to make one - ofs << " out[0] = wrap_shared_ptr(make_shared< " << returns_ << " >(result.first),\"" << returns_ << "\");\n"; + if (isPtr1) // if we already have a pointer + ofs << " out[0] = wrap_shared_ptr(result.first,\"" << type1 << "\");\n"; + else if (category1 == ReturnValue::CLASS) // if we are going to make one + ofs << " out[0] = wrap_shared_ptr(make_shared< " << type1 << " >(result.first),\"" << type1 << "\");\n"; else // if basis type ofs << " out[0] = wrap< " << return_type(true,arg1) << " >(result.first);\n"; // second return value in pair - if (returns_ptr2_) // if we already have a pointer - ofs << " out[1] = wrap_shared_ptr(result.second,\"" << returns2_ << "\");\n"; - else if (return2 == ReturnValue::CLASS) // if we are going to make one - ofs << " out[1] = wrap_shared_ptr(make_shared< " << returns2_ << " >(result.second),\"" << returns2_ << "\");\n"; + if (isPtr2) // if we already have a pointer + ofs << " out[1] = wrap_shared_ptr(result.second,\"" << type2 << "\");\n"; + else if (category2 == ReturnValue::CLASS) // if we are going to make one + ofs << " out[1] = wrap_shared_ptr(make_shared< " << type2 << " >(result.second),\"" << type2 << "\");\n"; else ofs << " out[1] = wrap< " << return_type(true,arg2) << " >(result.second);\n"; } - else if (returns_ptr_) - ofs << " out[0] = wrap_shared_ptr(result,\"" << returns_ << "\");\n"; - else if (return1 == ReturnValue::CLASS) - ofs << " out[0] = wrap_shared_ptr(make_shared< " << returns_ << " >(result),\"" << returns_ << "\");\n"; - else if (returns_!="void") + else if (isPtr1) + ofs << " out[0] = wrap_shared_ptr(result,\"" << type1 << "\");\n"; + else if (category1 == ReturnValue::CLASS) + ofs << " out[0] = wrap_shared_ptr(make_shared< " << type1 << " >(result),\"" << type1 << "\");\n"; + else if (type1!="void") ofs << " out[0] = wrap< " << return_type(true,arg1) << " >(result);\n"; } diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index a7137054f..c6d7864d3 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -22,16 +22,16 @@ struct ReturnValue { VOID } return_category; - ReturnValue(bool verbose = true) - : verbose_(verbose), returns_ptr_(false), returns_ptr2_(false), - returns_pair_(false), return1(VOID), return2(VOID) + ReturnValue(bool enable_verbosity = true) + : verbose(enable_verbosity), isPtr1(false), isPtr2(false), + isPair(false), category1(VOID), category2(VOID) {} - bool verbose_; - std::string returns_, returns2_; - bool returns_ptr_, returns_ptr2_, returns_pair_; + bool verbose; + std::string type1, type2; + bool isPtr1, isPtr2, isPair; - return_category return1, return2; + return_category category1, category2; typedef enum { arg1, arg2, pair @@ -39,7 +39,7 @@ struct ReturnValue { std::string return_type(bool add_ptr, pairing p); - std::string matlab_returnType() const { return returns_pair_? "[first,second]" : "result"; } + std::string matlab_returnType() const { return isPair? "[first,second]" : "result"; } void wrap_result(std::ostream& ofs); diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index 40ab9bcb8..763cb38f4 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -29,18 +29,18 @@ using namespace wrap; void StaticMethod::matlab_mfile(const string& toolboxPath, const string& className) { // open destination m-file - string full_name = className + "_" + name_; + string full_name = className + "_" + name; string wrapperFile = toolboxPath + "/" + full_name + ".m"; ofstream ofs(wrapperFile.c_str()); if(!ofs) throw CantOpenFile(wrapperFile); - if(verbose_) cerr << "generating " << wrapperFile << endl; + if(verbose) cerr << "generating " << wrapperFile << endl; // generate code - string returnType = returnVal_.matlab_returnType(); + string returnType = returnVal.matlab_returnType(); ofs << "function " << returnType << " = " << full_name << "("; - if (args_.size()) ofs << args_.names(); + if (args.size()) ofs << args.names(); ofs << ")" << endl; - ofs << "% usage: x = " << full_name << "(" << args_.names() << ")" << endl; + ofs << "% usage: x = " << full_name << "(" << args.names() << ")" << endl; ofs << " error('need to compile " << full_name << ".cpp');" << endl; ofs << "end" << endl; @@ -53,11 +53,11 @@ void StaticMethod::matlab_wrapper(const string& toolboxPath, const string& className, const string& nameSpace) { // open destination wrapperFile - string full_name = className + "_" + name_; + string full_name = className + "_" + name; string wrapperFile = toolboxPath + "/" + full_name + ".cpp"; ofstream ofs(wrapperFile.c_str()); if(!ofs) throw CantOpenFile(wrapperFile); - if(verbose_) cerr << "generating " << wrapperFile << endl; + if(verbose) cerr << "generating " << wrapperFile << endl; // generate code @@ -74,21 +74,21 @@ void StaticMethod::matlab_wrapper(const string& toolboxPath, // check arguments // NOTE: for static functions, there is no object passed - ofs << " checkArguments(\"" << full_name << "\",nargout,nargin," << args_.size() << ");\n"; + ofs << " checkArguments(\"" << full_name << "\",nargout,nargin," << args.size() << ");\n"; // unwrap arguments, see Argument.cpp - args_.matlab_unwrap(ofs,0); // We start at 0 because there is no self object + args.matlab_unwrap(ofs,0); // We start at 0 because there is no self object ofs << " "; // call method with default type - if (returnVal_.returns_!="void") - ofs << returnVal_.return_type(true,ReturnValue::pair) << " result = "; - ofs << className << "::" << name_ << "(" << args_.names() << ");\n"; + if (returnVal.type1!="void") + ofs << returnVal.return_type(true,ReturnValue::pair) << " result = "; + ofs << className << "::" << name << "(" << args.names() << ");\n"; // wrap result // example: out[0]=wrap(result); - returnVal_.wrap_result(ofs); + returnVal.wrap_result(ofs); // finish ofs << "}\n"; diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index 0366b64ef..c58b26fe8 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -30,14 +30,14 @@ namespace wrap { struct StaticMethod { /// Constructor creates empty object - StaticMethod(bool verbose = true) : - verbose_(verbose) {} + StaticMethod(bool verbosity = true) : + verbose(verbosity) {} // Then the instance variables are set directly by the Module constructor - bool verbose_; - std::string name_; - ArgumentList args_; - ReturnValue returnVal_; + bool verbose; + std::string name; + ArgumentList args; + ReturnValue returnVal; // MATLAB code generation // toolboxPath is the core toolbox directory, e.g., ../matlab diff --git a/wrap/geometry.h b/wrap/geometry.h index 2faa21504..8d598ba25 100644 --- a/wrap/geometry.h +++ b/wrap/geometry.h @@ -6,6 +6,7 @@ class Point2 { double x() const; double y() const; int dim() const; + VectorNotEigen vectorConfusion(); }; class Point3 { @@ -19,6 +20,10 @@ class Point3 { // another comment +/** + * A multi-line comment! + */ + class Test { /* a comment! */ // another comment @@ -31,6 +36,8 @@ class Test { int return_int (int value) const; double return_double (double value) const; + Test(double a, Matrix b); // a constructor in the middle of a class + // comments in the middle! // (more) comments in the middle! @@ -40,6 +47,7 @@ class Test { Matrix return_matrix1(Matrix value) const; Vector return_vector2(Vector value) const; Matrix return_matrix2(Matrix value) const; + void arg_EigenConstRef(const Matrix& value) const; bool return_field(const Test& t) const; diff --git a/wrap/tests/expected/@Test/Test.m b/wrap/tests/expected/@Test/Test.m index 19b4442e4..8574a0882 100644 --- a/wrap/tests/expected/@Test/Test.m +++ b/wrap/tests/expected/@Test/Test.m @@ -5,6 +5,7 @@ classdef Test methods function obj = Test(varargin) if nargin == 0, obj.self = new_Test_(); end + if nargin == 2, obj.self = new_Test_dM(varargin{1},varargin{2}); end if nargin ~= 13 && obj.self == 0, error('Test constructor failed'); end end function display(obj), obj.print(''); end diff --git a/wrap/tests/expected/Makefile b/wrap/tests/expected/Makefile index f839827e3..03f69a496 100644 --- a/wrap/tests/expected/Makefile +++ b/wrap/tests/expected/Makefile @@ -17,8 +17,10 @@ new_Point2_dd.$(MEXENDING): new_Point2_dd.cpp $(MEX) $(mex_flags) @Point2/y.cpp -output @Point2/y @Point2/dim.$(MEXENDING): @Point2/dim.cpp $(MEX) $(mex_flags) @Point2/dim.cpp -output @Point2/dim +@Point2/vectorConfusion.$(MEXENDING): @Point2/vectorConfusion.cpp + $(MEX) $(mex_flags) @Point2/vectorConfusion.cpp -output @Point2/vectorConfusion -Point2: new_Point2_.$(MEXENDING) new_Point2_dd.$(MEXENDING) @Point2/x.$(MEXENDING) @Point2/y.$(MEXENDING) @Point2/dim.$(MEXENDING) +Point2: new_Point2_.$(MEXENDING) new_Point2_dd.$(MEXENDING) @Point2/x.$(MEXENDING) @Point2/y.$(MEXENDING) @Point2/dim.$(MEXENDING) @Point2/vectorConfusion.$(MEXENDING) # Point3 new_Point3_ddd.$(MEXENDING): new_Point3_ddd.cpp @@ -35,6 +37,8 @@ Point3: new_Point3_ddd.$(MEXENDING) Point3_staticFunction.$(MEXENDING) Point3_St # Test new_Test_.$(MEXENDING): new_Test_.cpp $(MEX) $(mex_flags) new_Test_.cpp -output new_Test_ +new_Test_dM.$(MEXENDING): new_Test_dM.cpp + $(MEX) $(mex_flags) new_Test_dM.cpp -output new_Test_dM @Test/return_pair.$(MEXENDING): @Test/return_pair.cpp $(MEX) $(mex_flags) @Test/return_pair.cpp -output @Test/return_pair @Test/return_bool.$(MEXENDING): @Test/return_bool.cpp @@ -55,6 +59,8 @@ new_Test_.$(MEXENDING): new_Test_.cpp $(MEX) $(mex_flags) @Test/return_vector2.cpp -output @Test/return_vector2 @Test/return_matrix2.$(MEXENDING): @Test/return_matrix2.cpp $(MEX) $(mex_flags) @Test/return_matrix2.cpp -output @Test/return_matrix2 +@Test/arg_EigenConstRef.$(MEXENDING): @Test/arg_EigenConstRef.cpp + $(MEX) $(mex_flags) @Test/arg_EigenConstRef.cpp -output @Test/arg_EigenConstRef @Test/return_field.$(MEXENDING): @Test/return_field.cpp $(MEX) $(mex_flags) @Test/return_field.cpp -output @Test/return_field @Test/return_TestPtr.$(MEXENDING): @Test/return_TestPtr.cpp @@ -72,7 +78,7 @@ new_Test_.$(MEXENDING): new_Test_.cpp @Test/print.$(MEXENDING): @Test/print.cpp $(MEX) $(mex_flags) @Test/print.cpp -output @Test/print -Test: new_Test_.$(MEXENDING) @Test/return_pair.$(MEXENDING) @Test/return_bool.$(MEXENDING) @Test/return_size_t.$(MEXENDING) @Test/return_int.$(MEXENDING) @Test/return_double.$(MEXENDING) @Test/return_string.$(MEXENDING) @Test/return_vector1.$(MEXENDING) @Test/return_matrix1.$(MEXENDING) @Test/return_vector2.$(MEXENDING) @Test/return_matrix2.$(MEXENDING) @Test/return_field.$(MEXENDING) @Test/return_TestPtr.$(MEXENDING) @Test/return_Test.$(MEXENDING) @Test/return_Point2Ptr.$(MEXENDING) @Test/create_ptrs.$(MEXENDING) @Test/create_MixedPtrs.$(MEXENDING) @Test/return_ptrs.$(MEXENDING) @Test/print.$(MEXENDING) +Test: new_Test_.$(MEXENDING) new_Test_dM.$(MEXENDING) @Test/return_pair.$(MEXENDING) @Test/return_bool.$(MEXENDING) @Test/return_size_t.$(MEXENDING) @Test/return_int.$(MEXENDING) @Test/return_double.$(MEXENDING) @Test/return_string.$(MEXENDING) @Test/return_vector1.$(MEXENDING) @Test/return_matrix1.$(MEXENDING) @Test/return_vector2.$(MEXENDING) @Test/return_matrix2.$(MEXENDING) @Test/arg_EigenConstRef.$(MEXENDING) @Test/return_field.$(MEXENDING) @Test/return_TestPtr.$(MEXENDING) @Test/return_Test.$(MEXENDING) @Test/return_Point2Ptr.$(MEXENDING) @Test/create_ptrs.$(MEXENDING) @Test/create_MixedPtrs.$(MEXENDING) @Test/return_ptrs.$(MEXENDING) @Test/print.$(MEXENDING) diff --git a/wrap/tests/expected/make_geometry.m b/wrap/tests/expected/make_geometry.m index d73022bab..39123f65d 100644 --- a/wrap/tests/expected/make_geometry.m +++ b/wrap/tests/expected/make_geometry.m @@ -16,6 +16,7 @@ cd @Point2 mex -O5 x.cpp mex -O5 y.cpp mex -O5 dim.cpp +mex -O5 vectorConfusion.cpp %% Point3 cd(toolboxpath) @@ -29,6 +30,7 @@ mex -O5 norm.cpp %% Test cd(toolboxpath) mex -O5 new_Test_.cpp +mex -O5 new_Test_dM.cpp cd @Test mex -O5 return_pair.cpp @@ -41,6 +43,7 @@ mex -O5 return_vector1.cpp mex -O5 return_matrix1.cpp mex -O5 return_vector2.cpp mex -O5 return_matrix2.cpp +mex -O5 arg_EigenConstRef.cpp mex -O5 return_field.cpp mex -O5 return_TestPtr.cpp mex -O5 return_Test.cpp diff --git a/wrap/tests/testSpirit.cpp b/wrap/tests/testSpirit.cpp index 9683a3372..d4a6d151e 100644 --- a/wrap/tests/testSpirit.cpp +++ b/wrap/tests/testSpirit.cpp @@ -102,6 +102,40 @@ TEST( spirit, constMethod_p ) { EXPECT(parse("double norm() const;", constMethod_p, space_p).full); } +/* ************************************************************************* */ +TEST( spirit, return_value_p ) { + bool isEigen = true; + string actual_return_type; + string actual_function_name; + + Rule basisType_p = + (str_p("string") | "bool" | "size_t" | "int" | "double"); + + Rule eigenType_p = + (str_p("Vector") | "Matrix"); + + Rule className_p = lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - basisType_p; + + Rule funcName_p = lexeme_d[lower_p >> *(alnum_p | '_')]; + + Rule returnType_p = + (basisType_p[assign_a(actual_return_type)][assign_a(isEigen, true)]) | + (className_p[assign_a(actual_return_type)][assign_a(isEigen,false)]) | + (eigenType_p[assign_a(actual_return_type)][assign_a(isEigen, true)]); + + Rule testFunc_p = returnType_p >> funcName_p[assign_a(actual_function_name)] >> str_p("();"); + + EXPECT(parse("VectorNotEigen doesNotReturnAnEigenVector();", testFunc_p, space_p).full); + EXPECT(!isEigen); + EXPECT(actual_return_type == "VectorNotEigen"); + EXPECT(actual_function_name == "doesNotReturnAnEigenVector"); + + EXPECT(parse("Vector actuallyAVector();", testFunc_p, space_p).full); + EXPECT(isEigen); + EXPECT(actual_return_type == "Vector"); + EXPECT(actual_function_name == "actuallyAVector"); +} + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index b80412891..4cc8b7cd2 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace wrap; -static bool verbose = false; +static bool enable_verbose = false; #ifdef TOPSRCDIR static string topdir = TOPSRCDIR; #else @@ -46,15 +46,15 @@ TEST( wrap, ArgumentList ) { /* ************************************************************************* */ TEST( wrap, check_exception ) { - THROWS_EXCEPTION(Module("/notarealpath", "geometry",verbose)); - CHECK_EXCEPTION(Module("/alsonotarealpath", "geometry",verbose), CantOpenFile); + THROWS_EXCEPTION(Module("/notarealpath", "geometry",enable_verbose)); + CHECK_EXCEPTION(Module("/alsonotarealpath", "geometry",enable_verbose), CantOpenFile); } /* ************************************************************************* */ TEST( wrap, parse ) { string path = topdir + "/wrap"; - Module module(path.c_str(), "geometry",verbose); + Module module(path.c_str(), "geometry",enable_verbose); CHECK(module.classes.size()==3); // check second class, Point3 @@ -77,29 +77,29 @@ TEST( wrap, parse ) { // check method Method m1 = cls.methods.front(); - EXPECT(m1.returnVal_.returns_=="double"); + EXPECT(m1.returnVal_.type1=="double"); EXPECT(m1.name_=="norm"); EXPECT(m1.args_.size()==0); EXPECT(m1.is_const_); // Test class is the third one Class testCls = module.classes.at(2); - EXPECT_LONGS_EQUAL( 1, testCls.constructors.size()); - EXPECT_LONGS_EQUAL(18, testCls.methods.size()); + EXPECT_LONGS_EQUAL( 2, testCls.constructors.size()); + EXPECT_LONGS_EQUAL(19, testCls.methods.size()); EXPECT_LONGS_EQUAL( 0, testCls.static_methods.size()); -// pair return_pair (Vector v, Matrix A) const; + // function to parse: pair return_pair (Vector v, Matrix A) const; Method m2 = testCls.methods.front(); - EXPECT(m2.returnVal_.returns_pair_); - EXPECT(m2.returnVal_.return1 == ReturnValue::EIGEN); - EXPECT(m2.returnVal_.return2 == ReturnValue::EIGEN); + EXPECT(m2.returnVal_.isPair); + EXPECT(m2.returnVal_.category1 == ReturnValue::EIGEN); + EXPECT(m2.returnVal_.category2 == ReturnValue::EIGEN); } /* ************************************************************************* */ TEST( wrap, matlab_code ) { // Parse into class object string path = topdir + "/wrap"; - Module module(path,"geometry",verbose); + Module module(path,"geometry",enable_verbose); // emit MATLAB code // make_geometry will not compile, use make testwrap to generate real make