Added a check that all wrapped classes involved in a heirarchy are marked virtual

release/4.3a0
Richard Roberts 2012-07-10 22:38:21 +00:00
parent e337ab8b1d
commit 0c384dc35a
3 changed files with 436 additions and 417 deletions

10
gtsam.h
View File

@ -702,17 +702,17 @@ class VariableIndex {
#include <gtsam/linear/NoiseModel.h> #include <gtsam/linear/NoiseModel.h>
namespace noiseModel { namespace noiseModel {
class Base { virtual class Base {
}; };
class Gaussian : gtsam::noiseModel::Base { virtual class Gaussian : gtsam::noiseModel::Base {
static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R); static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R);
static gtsam::noiseModel::Gaussian* Covariance(Matrix R); static gtsam::noiseModel::Gaussian* Covariance(Matrix R);
// Matrix R() const; // FIXME: cannot parse!!! // Matrix R() const; // FIXME: cannot parse!!!
void print(string s) const; void print(string s) const;
}; };
class Diagonal : gtsam::noiseModel::Gaussian { virtual class Diagonal : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas); static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas);
static gtsam::noiseModel::Diagonal* Variances(Vector variances); static gtsam::noiseModel::Diagonal* Variances(Vector variances);
static gtsam::noiseModel::Diagonal* Precisions(Vector precisions); static gtsam::noiseModel::Diagonal* Precisions(Vector precisions);
@ -720,14 +720,14 @@ class Diagonal : gtsam::noiseModel::Gaussian {
void print(string s) const; void print(string s) const;
}; };
class Isotropic : gtsam::noiseModel::Gaussian { virtual class Isotropic : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma); static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma);
static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace); static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace);
static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision); static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision);
void print(string s) const; void print(string s) const;
}; };
class Unit : gtsam::noiseModel::Gaussian { virtual class Unit : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Unit* Create(size_t dim); static gtsam::noiseModel::Unit* Create(size_t dim);
void print(string s) const; void print(string s) const;
}; };

View File

@ -1,355 +1,355 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation, * GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415 * Atlanta, Georgia 30332-0415
* All Rights Reserved * All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list) * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information * See LICENSE for the license information
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/** /**
* @file Module.ccp * @file Module.ccp
* @author Frank Dellaert * @author Frank Dellaert
* @author Alex Cunningham * @author Alex Cunningham
* @author Andrew Melim * @author Andrew Melim
**/ **/
#include "Module.h" #include "Module.h"
#include "FileWriter.h" #include "FileWriter.h"
#include "utilities.h" #include "utilities.h"
#include "spirit_actors.h" #include "spirit_actors.h"
//#define BOOST_SPIRIT_DEBUG //#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/classic_confix.hpp> #include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_clear_actor.hpp> #include <boost/spirit/include/classic_clear_actor.hpp>
#include <boost/spirit/include/classic_insert_at_actor.hpp> #include <boost/spirit/include/classic_insert_at_actor.hpp>
#include <boost/lambda/bind.hpp> #include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp> #include <boost/lambda/construct.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
using namespace std; using namespace std;
using namespace wrap; using namespace wrap;
using namespace BOOST_SPIRIT_CLASSIC_NS; using namespace BOOST_SPIRIT_CLASSIC_NS;
namespace bl = boost::lambda; namespace bl = boost::lambda;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
typedef rule<BOOST_SPIRIT_CLASSIC_NS::phrase_scanner_t> Rule; typedef rule<BOOST_SPIRIT_CLASSIC_NS::phrase_scanner_t> Rule;
/* ************************************************************************* */ /* ************************************************************************* */
// We parse an interface file into a Module object. // We parse an interface file into a Module object.
// The grammar is defined using the boost/spirit combinatorial parser. // The grammar is defined using the boost/spirit combinatorial parser.
// For example, str_p("const") parses the string "const", and the >> // For example, str_p("const") parses the string "const", and the >>
// operator creates a sequence parser. The grammar below, composed of rules // operator creates a sequence parser. The grammar below, composed of rules
// and with start rule [class_p], doubles as the specs for our interface files. // and with start rule [class_p], doubles as the specs for our interface files.
/* ************************************************************************* */ /* ************************************************************************* */
Module::Module(const string& interfacePath, Module::Module(const string& interfacePath,
const string& moduleName, bool enable_verbose) : name(moduleName), verbose(enable_verbose) const string& moduleName, bool enable_verbose) : name(moduleName), verbose(enable_verbose)
{ {
// these variables will be imperatively updated to gradually build [cls] // these variables will be imperatively updated to gradually build [cls]
// The one with postfix 0 are used to reset the variables after parse. // The one with postfix 0 are used to reset the variables after parse.
string methodName, methodName0; string methodName, methodName0;
bool isConst, isConst0 = false; bool isConst, isConst0 = false;
ReturnValue retVal0, retVal; ReturnValue retVal0, retVal;
Argument arg0, arg; Argument arg0, arg;
ArgumentList args0, args; ArgumentList args0, args;
vector<string> arg_dup; ///keep track of duplicates vector<string> arg_dup; ///keep track of duplicates
Constructor constructor0(enable_verbose), constructor(enable_verbose); Constructor constructor0(enable_verbose), constructor(enable_verbose);
Deconstructor deconstructor0(enable_verbose), deconstructor(enable_verbose); Deconstructor deconstructor0(enable_verbose), deconstructor(enable_verbose);
//Method method0(enable_verbose), method(enable_verbose); //Method method0(enable_verbose), method(enable_verbose);
StaticMethod static_method0(enable_verbose), static_method(enable_verbose); StaticMethod static_method0(enable_verbose), static_method(enable_verbose);
Class cls0(enable_verbose),cls(enable_verbose); Class cls0(enable_verbose),cls(enable_verbose);
ForwardDeclaration fwDec0, fwDec; ForwardDeclaration fwDec0, fwDec;
vector<string> namespaces, /// current namespace tag vector<string> namespaces, /// current namespace tag
namespace_includes, /// current set of includes namespace_includes, /// current set of includes
namespaces_return, /// namespace for current return type namespaces_return, /// namespace for current return type
using_namespace_current; /// All namespaces from "using" declarations using_namespace_current; /// All namespaces from "using" declarations
string include_path = ""; string include_path = "";
const string null_str = ""; const string null_str = "";
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Grammar with actions that build the Class object. Actions are // Grammar with actions that build the Class object. Actions are
// defined within the square brackets [] and are executed whenever a // defined within the square brackets [] and are executed whenever a
// rule is successfully parsed. Define BOOST_SPIRIT_DEBUG to debug. // rule is successfully parsed. Define BOOST_SPIRIT_DEBUG to debug.
// The grammar is allows a very restricted C++ header // The grammar is allows a very restricted C++ header
// lexeme_d turns off white space skipping // lexeme_d turns off white space skipping
// http://www.boost.org/doc/libs/1_37_0/libs/spirit/classic/doc/directives.html // http://www.boost.org/doc/libs/1_37_0/libs/spirit/classic/doc/directives.html
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Rule comments_p = comment_p("/*", "*/") | comment_p("//", eol_p); Rule comments_p = comment_p("/*", "*/") | comment_p("//", eol_p);
Rule basisType_p = Rule basisType_p =
(str_p("string") | "bool" | "size_t" | "int" | "double" | "char" | "unsigned char"); (str_p("string") | "bool" | "size_t" | "int" | "double" | "char" | "unsigned char");
Rule keywords_p = Rule keywords_p =
(str_p("const") | "static" | "namespace" | basisType_p); (str_p("const") | "static" | "namespace" | basisType_p);
Rule eigenType_p = Rule eigenType_p =
(str_p("Vector") | "Matrix"); (str_p("Vector") | "Matrix");
Rule className_p = (lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - keywords_p); Rule className_p = (lexeme_d[upper_p >> *(alnum_p | '_')] - eigenType_p - keywords_p);
Rule namespace_name_p = lexeme_d[lower_p >> *(alnum_p | '_')] - keywords_p; Rule namespace_name_p = lexeme_d[lower_p >> *(alnum_p | '_')] - keywords_p;
Rule namespace_arg_p = namespace_name_p[push_back_a(arg.namespaces)] >> str_p("::"); Rule namespace_arg_p = namespace_name_p[push_back_a(arg.namespaces)] >> str_p("::");
Rule argEigenType_p = Rule argEigenType_p =
eigenType_p[assign_a(arg.type)] >> eigenType_p[assign_a(arg.type)] >>
!ch_p('*')[assign_a(arg.is_ptr,true)]; !ch_p('*')[assign_a(arg.is_ptr,true)];
Rule eigenRef_p = Rule eigenRef_p =
!str_p("const") [assign_a(arg.is_const,true)] >> !str_p("const") [assign_a(arg.is_const,true)] >>
eigenType_p [assign_a(arg.type)] >> eigenType_p [assign_a(arg.type)] >>
ch_p('&') [assign_a(arg.is_ref,true)]; ch_p('&') [assign_a(arg.is_ref,true)];
Rule classArg_p = Rule classArg_p =
!str_p("const") [assign_a(arg.is_const,true)] >> !str_p("const") [assign_a(arg.is_const,true)] >>
*namespace_arg_p >> *namespace_arg_p >>
className_p[assign_a(arg.type)] >> className_p[assign_a(arg.type)] >>
(ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]); (ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]);
Rule classParent_p = Rule classParent_p =
*(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >> *(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >>
className_p[push_back_a(cls.qualifiedParent)]; className_p[push_back_a(cls.qualifiedParent)];
Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')]; Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')];
Rule argument_p = Rule argument_p =
((basisType_p[assign_a(arg.type)] | argEigenType_p | eigenRef_p | classArg_p) ((basisType_p[assign_a(arg.type)] | argEigenType_p | eigenRef_p | classArg_p)
>> name_p[assign_a(arg.name)]) >> name_p[assign_a(arg.name)])
[push_back_a(args, arg)] [push_back_a(args, arg)]
[assign_a(arg,arg0)]; [assign_a(arg,arg0)];
Rule argumentList_p = !argument_p >> * (',' >> argument_p); Rule argumentList_p = !argument_p >> * (',' >> argument_p);
Rule constructor_p = Rule constructor_p =
(className_p >> '(' >> argumentList_p >> ')' >> ';' >> !comments_p) (className_p >> '(' >> argumentList_p >> ')' >> ';' >> !comments_p)
[push_back_a(constructor.args_list, args)] [push_back_a(constructor.args_list, args)]
[assign_a(args,args0)]; [assign_a(args,args0)];
//[assign_a(constructor.args,args)] //[assign_a(constructor.args,args)]
//[assign_a(constructor.name,cls.name)] //[assign_a(constructor.name,cls.name)]
//[push_back_a(cls.constructors, constructor)] //[push_back_a(cls.constructors, constructor)]
//[assign_a(constructor,constructor0)]; //[assign_a(constructor,constructor0)];
Rule namespace_ret_p = namespace_name_p[push_back_a(namespaces_return)] >> str_p("::"); Rule namespace_ret_p = namespace_name_p[push_back_a(namespaces_return)] >> str_p("::");
Rule returnType1_p = Rule returnType1_p =
(basisType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::BASIS)]) | (basisType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::BASIS)]) |
((*namespace_ret_p)[assign_a(retVal.namespaces1, namespaces_return)][clear_a(namespaces_return)] ((*namespace_ret_p)[assign_a(retVal.namespaces1, namespaces_return)][clear_a(namespaces_return)]
>> (className_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::CLASS)]) >> >> (className_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::CLASS)]) >>
!ch_p('*')[assign_a(retVal.isPtr1,true)]) | !ch_p('*')[assign_a(retVal.isPtr1,true)]) |
(eigenType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::EIGEN)]); (eigenType_p[assign_a(retVal.type1)][assign_a(retVal.category1, ReturnValue::EIGEN)]);
Rule returnType2_p = Rule returnType2_p =
(basisType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::BASIS)]) | (basisType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::BASIS)]) |
((*namespace_ret_p)[assign_a(retVal.namespaces2, namespaces_return)][clear_a(namespaces_return)] ((*namespace_ret_p)[assign_a(retVal.namespaces2, namespaces_return)][clear_a(namespaces_return)]
>> (className_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::CLASS)]) >> >> (className_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::CLASS)]) >>
!ch_p('*') [assign_a(retVal.isPtr2,true)]) | !ch_p('*') [assign_a(retVal.isPtr2,true)]) |
(eigenType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::EIGEN)]); (eigenType_p[assign_a(retVal.type2)][assign_a(retVal.category2, ReturnValue::EIGEN)]);
Rule pair_p = Rule pair_p =
(str_p("pair") >> '<' >> returnType1_p >> ',' >> returnType2_p >> '>') (str_p("pair") >> '<' >> returnType1_p >> ',' >> returnType2_p >> '>')
[assign_a(retVal.isPair,true)]; [assign_a(retVal.isPair,true)];
Rule void_p = str_p("void")[assign_a(retVal.type1)]; Rule void_p = str_p("void")[assign_a(retVal.type1)];
Rule returnType_p = void_p | returnType1_p | pair_p; Rule returnType_p = void_p | returnType1_p | pair_p;
Rule methodName_p = lexeme_d[lower_p >> *(alnum_p | '_')]; Rule methodName_p = lexeme_d[lower_p >> *(alnum_p | '_')];
Rule method_p = Rule method_p =
(returnType_p >> methodName_p[assign_a(methodName)] >> (returnType_p >> methodName_p[assign_a(methodName)] >>
'(' >> argumentList_p >> ')' >> '(' >> argumentList_p >> ')' >>
!str_p("const")[assign_a(isConst,true)] >> ';' >> *comments_p) !str_p("const")[assign_a(isConst,true)] >> ';' >> *comments_p)
[bl::bind(&Method::addOverload, [bl::bind(&Method::addOverload,
bl::var(cls.methods)[bl::var(methodName)], bl::var(cls.methods)[bl::var(methodName)],
verbose, verbose,
bl::var(isConst), bl::var(isConst),
bl::var(methodName), bl::var(methodName),
bl::var(args), bl::var(args),
bl::var(retVal))] bl::var(retVal))]
[assign_a(isConst,isConst0)] [assign_a(isConst,isConst0)]
[assign_a(methodName,methodName0)] [assign_a(methodName,methodName0)]
[assign_a(args,args0)] [assign_a(args,args0)]
[assign_a(retVal,retVal0)]; [assign_a(retVal,retVal0)];
Rule staticMethodName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')]; Rule staticMethodName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')];
Rule static_method_p = Rule static_method_p =
(str_p("static") >> returnType_p >> staticMethodName_p[assign_a(methodName)] >> (str_p("static") >> returnType_p >> staticMethodName_p[assign_a(methodName)] >>
'(' >> argumentList_p >> ')' >> ';' >> *comments_p) '(' >> argumentList_p >> ')' >> ';' >> *comments_p)
[bl::bind(&StaticMethod::addOverload, [bl::bind(&StaticMethod::addOverload,
bl::var(cls.static_methods)[bl::var(methodName)], bl::var(cls.static_methods)[bl::var(methodName)],
verbose, verbose,
bl::var(methodName), bl::var(methodName),
bl::var(args), bl::var(args),
bl::var(retVal))] bl::var(retVal))]
[assign_a(methodName,methodName0)] [assign_a(methodName,methodName0)]
[assign_a(args,args0)] [assign_a(args,args0)]
[assign_a(retVal,retVal0)]; [assign_a(retVal,retVal0)];
Rule functions_p = constructor_p | method_p | static_method_p; Rule functions_p = constructor_p | method_p | static_method_p;
Rule include_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[assign_a(include_path)] >> ch_p('>'); Rule include_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[assign_a(include_path)] >> ch_p('>');
Rule class_p = Rule class_p =
(!*include_p (!*include_p
>> !(str_p("virtual")[assign_a(cls.isVirtual, true)]) >> !(str_p("virtual")[assign_a(cls.isVirtual, true)])
>> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)] >> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)]
>> className_p[assign_a(cls.name)] >> className_p[assign_a(cls.name)]
>> ((':' >> classParent_p >> '{') | '{') // By having (parent >> '{' | '{') here instead of (!parent >> '{'), we trigger a parse error on a badly-formed parent spec >> ((':' >> classParent_p >> '{') | '{') // By having (parent >> '{' | '{') here instead of (!parent >> '{'), we trigger a parse error on a badly-formed parent spec
>> *(functions_p | comments_p) >> *(functions_p | comments_p)
>> str_p("};")) >> str_p("};"))
[assign_a(constructor.name, cls.name)] [assign_a(constructor.name, cls.name)]
[assign_a(cls.constructor, constructor)] [assign_a(cls.constructor, constructor)]
[assign_a(cls.namespaces, namespaces)] [assign_a(cls.namespaces, namespaces)]
[assign_a(cls.using_namespaces, using_namespace_current)] [assign_a(cls.using_namespaces, using_namespace_current)]
[append_a(cls.includes, namespace_includes)] [append_a(cls.includes, namespace_includes)]
[assign_a(deconstructor.name,cls.name)] [assign_a(deconstructor.name,cls.name)]
[assign_a(cls.deconstructor, deconstructor)] [assign_a(cls.deconstructor, deconstructor)]
[push_back_a(classes, cls)] [push_back_a(classes, cls)]
[assign_a(deconstructor,deconstructor0)] [assign_a(deconstructor,deconstructor0)]
[assign_a(constructor, constructor0)] [assign_a(constructor, constructor0)]
[assign_a(cls,cls0)]; [assign_a(cls,cls0)];
Rule namespace_def_p = Rule namespace_def_p =
(!*include_p (!*include_p
>> str_p("namespace")[push_back_a(namespace_includes, include_path)][assign_a(include_path, null_str)] >> str_p("namespace")[push_back_a(namespace_includes, include_path)][assign_a(include_path, null_str)]
>> namespace_name_p[push_back_a(namespaces)] >> namespace_name_p[push_back_a(namespaces)]
>> ch_p('{') >> ch_p('{')
>> *(class_p | namespace_def_p | comments_p) >> *(class_p | namespace_def_p | comments_p)
>> str_p("}///\\namespace") // end namespace, avoid confusion with classes >> str_p("}///\\namespace") // end namespace, avoid confusion with classes
>> !namespace_name_p) >> !namespace_name_p)
[pop_a(namespaces)] [pop_a(namespaces)]
[pop_a(namespace_includes)]; [pop_a(namespace_includes)];
Rule using_namespace_p = Rule using_namespace_p =
str_p("using") >> str_p("namespace") str_p("using") >> str_p("namespace")
>> namespace_name_p[push_back_a(using_namespace_current)] >> ch_p(';'); >> namespace_name_p[push_back_a(using_namespace_current)] >> ch_p(';');
Rule forward_declaration_p = Rule forward_declaration_p =
!(str_p("virtual")[assign_a(fwDec.isVirtual, true)]) !(str_p("virtual")[assign_a(fwDec.isVirtual, true)])
>> str_p("class") >> str_p("class")
>> (*(namespace_name_p >> str_p("::")) >> className_p)[assign_a(fwDec.name)] >> (*(namespace_name_p >> str_p("::")) >> className_p)[assign_a(fwDec.name)]
>> ch_p(';') >> ch_p(';')
[push_back_a(forward_declarations, fwDec)] [push_back_a(forward_declarations, fwDec)]
[assign_a(fwDec, fwDec0)]; [assign_a(fwDec, fwDec0)];
Rule module_content_p = comments_p | using_namespace_p | class_p | forward_declaration_p | namespace_def_p ; Rule module_content_p = comments_p | using_namespace_p | class_p | forward_declaration_p | namespace_def_p ;
Rule module_p = *module_content_p >> !end_p; Rule module_p = *module_content_p >> !end_p;
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// for debugging, define BOOST_SPIRIT_DEBUG // for debugging, define BOOST_SPIRIT_DEBUG
# ifdef BOOST_SPIRIT_DEBUG # ifdef BOOST_SPIRIT_DEBUG
BOOST_SPIRIT_DEBUG_NODE(className_p); BOOST_SPIRIT_DEBUG_NODE(className_p);
BOOST_SPIRIT_DEBUG_NODE(classPtr_p); BOOST_SPIRIT_DEBUG_NODE(classPtr_p);
BOOST_SPIRIT_DEBUG_NODE(classRef_p); BOOST_SPIRIT_DEBUG_NODE(classRef_p);
BOOST_SPIRIT_DEBUG_NODE(basisType_p); BOOST_SPIRIT_DEBUG_NODE(basisType_p);
BOOST_SPIRIT_DEBUG_NODE(name_p); BOOST_SPIRIT_DEBUG_NODE(name_p);
BOOST_SPIRIT_DEBUG_NODE(argument_p); BOOST_SPIRIT_DEBUG_NODE(argument_p);
BOOST_SPIRIT_DEBUG_NODE(argumentList_p); BOOST_SPIRIT_DEBUG_NODE(argumentList_p);
BOOST_SPIRIT_DEBUG_NODE(constructor_p); BOOST_SPIRIT_DEBUG_NODE(constructor_p);
BOOST_SPIRIT_DEBUG_NODE(returnType1_p); BOOST_SPIRIT_DEBUG_NODE(returnType1_p);
BOOST_SPIRIT_DEBUG_NODE(returnType2_p); BOOST_SPIRIT_DEBUG_NODE(returnType2_p);
BOOST_SPIRIT_DEBUG_NODE(pair_p); BOOST_SPIRIT_DEBUG_NODE(pair_p);
BOOST_SPIRIT_DEBUG_NODE(void_p); BOOST_SPIRIT_DEBUG_NODE(void_p);
BOOST_SPIRIT_DEBUG_NODE(returnType_p); BOOST_SPIRIT_DEBUG_NODE(returnType_p);
BOOST_SPIRIT_DEBUG_NODE(methodName_p); BOOST_SPIRIT_DEBUG_NODE(methodName_p);
BOOST_SPIRIT_DEBUG_NODE(method_p); BOOST_SPIRIT_DEBUG_NODE(method_p);
BOOST_SPIRIT_DEBUG_NODE(class_p); BOOST_SPIRIT_DEBUG_NODE(class_p);
BOOST_SPIRIT_DEBUG_NODE(namespace_def_p); BOOST_SPIRIT_DEBUG_NODE(namespace_def_p);
BOOST_SPIRIT_DEBUG_NODE(module_p); BOOST_SPIRIT_DEBUG_NODE(module_p);
# endif # endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// read interface file // read interface file
string interfaceFile = interfacePath + "/" + moduleName + ".h"; string interfaceFile = interfacePath + "/" + moduleName + ".h";
string contents = file_contents(interfaceFile); string contents = file_contents(interfaceFile);
// and parse contents // and parse contents
parse_info<const char*> info = parse(contents.c_str(), module_p, space_p); parse_info<const char*> info = parse(contents.c_str(), module_p, space_p);
if(!info.full) { if(!info.full) {
printf("parsing stopped at \n%.20s\n",info.stop); printf("parsing stopped at \n%.20s\n",info.stop);
throw ParseFailed(info.length); throw ParseFailed(info.length);
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class T> template<class T>
void verifyArguments(const vector<string>& validArgs, const map<string,T>& vt) { void verifyArguments(const vector<string>& validArgs, const map<string,T>& vt) {
typedef typename map<string,T>::value_type Name_Method; typedef typename map<string,T>::value_type Name_Method;
BOOST_FOREACH(const Name_Method& name_method, vt) { BOOST_FOREACH(const Name_Method& name_method, vt) {
const T& t = name_method.second; const T& t = name_method.second;
BOOST_FOREACH(const ArgumentList& argList, t.argLists) { BOOST_FOREACH(const ArgumentList& argList, t.argLists) {
BOOST_FOREACH(Argument arg, argList) { BOOST_FOREACH(Argument arg, argList) {
string fullType = arg.qualifiedType("::"); string fullType = arg.qualifiedType("::");
if(find(validArgs.begin(), validArgs.end(), fullType) if(find(validArgs.begin(), validArgs.end(), fullType)
== validArgs.end()) == validArgs.end())
throw DependencyMissing(fullType, t.name); throw DependencyMissing(fullType, t.name);
} }
} }
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
template<class T> template<class T>
void verifyReturnTypes(const vector<string>& validtypes, const map<string,T>& vt) { void verifyReturnTypes(const vector<string>& validtypes, const map<string,T>& vt) {
typedef typename map<string,T>::value_type Name_Method; typedef typename map<string,T>::value_type Name_Method;
BOOST_FOREACH(const Name_Method& name_method, vt) { BOOST_FOREACH(const Name_Method& name_method, vt) {
const T& t = name_method.second; const T& t = name_method.second;
BOOST_FOREACH(const ReturnValue& retval, t.returnVals) { BOOST_FOREACH(const ReturnValue& retval, t.returnVals) {
if (find(validtypes.begin(), validtypes.end(), retval.qualifiedType1("::")) == validtypes.end()) if (find(validtypes.begin(), validtypes.end(), retval.qualifiedType1("::")) == validtypes.end())
throw DependencyMissing(retval.qualifiedType1("::"), t.name); throw DependencyMissing(retval.qualifiedType1("::"), t.name);
if (retval.isPair && find(validtypes.begin(), validtypes.end(), retval.qualifiedType2("::")) == validtypes.end()) if (retval.isPair && find(validtypes.begin(), validtypes.end(), retval.qualifiedType2("::")) == validtypes.end())
throw DependencyMissing(retval.qualifiedType2("::"), t.name); throw DependencyMissing(retval.qualifiedType2("::"), t.name);
} }
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Module::matlab_code(const string& toolboxPath, const string& headerPath) const { void Module::matlab_code(const string& toolboxPath, const string& headerPath) const {
fs::create_directories(toolboxPath); fs::create_directories(toolboxPath);
// create the unified .cpp switch file // create the unified .cpp switch file
const string wrapperName = name + "_wrapper"; const string wrapperName = name + "_wrapper";
string wrapperFileName = toolboxPath + "/" + wrapperName + ".cpp"; string wrapperFileName = toolboxPath + "/" + wrapperName + ".cpp";
FileWriter wrapperFile(wrapperFileName, verbose, "//"); FileWriter wrapperFile(wrapperFileName, verbose, "//");
vector<string> functionNames; // Function names stored by index for switch vector<string> functionNames; // Function names stored by index for switch
wrapperFile.oss << "#include <wrap/matlab.h>\n"; wrapperFile.oss << "#include <wrap/matlab.h>\n";
wrapperFile.oss << "#include <map>\n"; wrapperFile.oss << "#include <map>\n";
wrapperFile.oss << "#include <boost/foreach.hpp>\n"; wrapperFile.oss << "#include <boost/foreach.hpp>\n";
wrapperFile.oss << "\n"; wrapperFile.oss << "\n";
// Dependency check list // Dependency check list
vector<string> validTypes; vector<string> validTypes;
BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) { BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) {
validTypes.push_back(fwDec.name); validTypes.push_back(fwDec.name);
} }
validTypes.push_back("void"); validTypes.push_back("void");
validTypes.push_back("string"); validTypes.push_back("string");
validTypes.push_back("int"); validTypes.push_back("int");
validTypes.push_back("bool"); validTypes.push_back("bool");
validTypes.push_back("char"); validTypes.push_back("char");
validTypes.push_back("unsigned char"); validTypes.push_back("unsigned char");
validTypes.push_back("size_t"); validTypes.push_back("size_t");
validTypes.push_back("double"); validTypes.push_back("double");
validTypes.push_back("Vector"); validTypes.push_back("Vector");
validTypes.push_back("Matrix"); validTypes.push_back("Matrix");
//Create a list of parsed classes for dependency checking //Create a list of parsed classes for dependency checking
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
validTypes.push_back(cls.qualifiedName("::")); validTypes.push_back(cls.qualifiedName("::"));
} }
// Create type attributes table // Create type attributes table
ReturnValue::TypeAttributesTable typeAttributes; ReturnValue::TypeAttributesTable typeAttributes;
BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) { BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) {
@ -359,71 +359,80 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
if(!typeAttributes.insert(make_pair(cls.qualifiedName("::"), ReturnValue::TypeAttributes(cls.isVirtual))).second) if(!typeAttributes.insert(make_pair(cls.qualifiedName("::"), ReturnValue::TypeAttributes(cls.isVirtual))).second)
throw DuplicateDefinition("class " + cls.qualifiedName("::")); throw DuplicateDefinition("class " + cls.qualifiedName("::"));
// Check that class is virtual if it has a parent
} }
// Check attributes
// Check that all classes have been defined somewhere
BOOST_FOREACH(const Class& cls, classes) {
// verify all of the function arguments
//TODO:verifyArguments<ArgumentList>(validTypes, cls.constructor.args_list);
verifyArguments<StaticMethod>(validTypes, cls.static_methods);
verifyArguments<Method>(validTypes, cls.methods);
// verify function return types
verifyReturnTypes<StaticMethod>(validTypes, cls.static_methods);
verifyReturnTypes<Method>(validTypes, cls.methods);
}
// Generate all includes
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
generateIncludes(wrapperFile, cls.name, cls.includes); // Check that class is virtual if it has a parent
} if(!cls.qualifiedParent.empty() && !cls.isVirtual)
wrapperFile.oss << "\n"; throw AttributeError(cls.qualifiedName("::"), "Has a base class so needs to be declared virtual, change to 'virtual class "+cls.name+" ...'");
// Check that parent is virtual as well
// Generate all collectors if(!cls.qualifiedParent.empty() && !typeAttributes.at(wrap::qualifiedName("::", cls.qualifiedParent)).isVirtual)
throw AttributeError(wrap::qualifiedName("::", cls.qualifiedParent),
"Is the base class of " + cls.qualifiedName("::") + ", so needs to be declared virtual");
}
// Check that all classes have been defined somewhere
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::"); // verify all of the function arguments
wrapperFile.oss << "typedef std::set<boost::shared_ptr<" << cppName << ">*> " //TODO:verifyArguments<ArgumentList>(validTypes, cls.constructor.args_list);
<< "Collector_" << matlabName << ";\n"; verifyArguments<StaticMethod>(validTypes, cls.static_methods);
wrapperFile.oss << "static Collector_" << matlabName << verifyArguments<Method>(validTypes, cls.methods);
" collector_" << matlabName << ";\n";
} // verify function return types
verifyReturnTypes<StaticMethod>(validTypes, cls.static_methods);
// generate mexAtExit cleanup function verifyReturnTypes<Method>(validTypes, cls.methods);
wrapperFile.oss << "void _deleteAllObjects()\n"; }
wrapperFile.oss << "{\n";
// Generate all includes
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
const string matlabName = cls.qualifiedName(); generateIncludes(wrapperFile, cls.name, cls.includes);
const string cppName = cls.qualifiedName("::"); }
const string collectorType = "Collector_" + matlabName; wrapperFile.oss << "\n";
const string collectorName = "collector_" + matlabName;
wrapperFile.oss << " for(" << collectorType << "::iterator iter = " << collectorName << ".begin();\n"; // Generate all collectors
wrapperFile.oss << " iter != " << collectorName << ".end(); ) {\n";
wrapperFile.oss << " delete *iter;\n";
wrapperFile.oss << " " << collectorName << ".erase(iter++);\n";
wrapperFile.oss << " }\n";
}
wrapperFile.oss << "}\n";
// create proxy class and wrapper code
BOOST_FOREACH(const Class& cls, classes) { BOOST_FOREACH(const Class& cls, classes) {
string classFile = toolboxPath + "/" + cls.qualifiedName() + ".m"; const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::");
cls.matlab_proxy(classFile, wrapperName, typeAttributes, wrapperFile, functionNames); wrapperFile.oss << "typedef std::set<boost::shared_ptr<" << cppName << ">*> "
} << "Collector_" << matlabName << ";\n";
wrapperFile.oss << "static Collector_" << matlabName <<
// finish wrapper file " collector_" << matlabName << ";\n";
finish_wrapper(wrapperFile, functionNames); }
wrapperFile.emit(true); // generate mexAtExit cleanup function
} wrapperFile.oss << "\nvoid _deleteAllObjects()\n";
wrapperFile.oss << "{\n";
/* ************************************************************************* */ BOOST_FOREACH(const Class& cls, classes) {
void Module::finish_wrapper(FileWriter& file, const std::vector<std::string>& functionNames) const { const string matlabName = cls.qualifiedName();
file.oss << "void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n"; const string cppName = cls.qualifiedName("::");
file.oss << "{\n"; const string collectorType = "Collector_" + matlabName;
const string collectorName = "collector_" + matlabName;
wrapperFile.oss << " for(" << collectorType << "::iterator iter = " << collectorName << ".begin();\n";
wrapperFile.oss << " iter != " << collectorName << ".end(); ) {\n";
wrapperFile.oss << " delete *iter;\n";
wrapperFile.oss << " " << collectorName << ".erase(iter++);\n";
wrapperFile.oss << " }\n";
}
wrapperFile.oss << "}\n";
// create proxy class and wrapper code
BOOST_FOREACH(const Class& cls, classes) {
string classFile = toolboxPath + "/" + cls.qualifiedName() + ".m";
cls.matlab_proxy(classFile, wrapperName, typeAttributes, wrapperFile, functionNames);
}
// finish wrapper file
wrapperFile.oss << "\n";
finish_wrapper(wrapperFile, functionNames);
wrapperFile.emit(true);
}
/* ************************************************************************* */
void Module::finish_wrapper(FileWriter& file, const std::vector<std::string>& functionNames) const {
file.oss << "void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n";
file.oss << "{\n";
file.oss << " mstream mout;\n"; // Send stdout to MATLAB console, see matlab.h file.oss << " mstream mout;\n"; // Send stdout to MATLAB console, see matlab.h
file.oss << " std::streambuf *outbuf = std::cout.rdbuf(&mout);\n\n"; file.oss << " std::streambuf *outbuf = std::cout.rdbuf(&mout);\n\n";
file.oss << " int id = unwrap<int>(in[0]);\n\n"; file.oss << " int id = unwrap<int>(in[0]);\n\n";
file.oss << " switch(id) {\n"; file.oss << " switch(id) {\n";
for(size_t id = 0; id < functionNames.size(); ++id) { for(size_t id = 0; id < functionNames.size(); ++id) {
@ -433,8 +442,8 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
} }
file.oss << " }\n"; file.oss << " }\n";
file.oss << "\n"; file.oss << "\n";
file.oss << " std::cout.rdbuf(outbuf);\n"; // Restore cout, see matlab.h file.oss << " std::cout.rdbuf(outbuf);\n"; // Restore cout, see matlab.h
file.oss << "}\n"; file.oss << "}\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -68,6 +68,16 @@ public:
~DuplicateDefinition() throw() {} ~DuplicateDefinition() throw() {}
virtual const char* what() const throw() { return what_.c_str(); } virtual const char* what() const throw() { return what_.c_str(); }
}; };
class AttributeError : public std::exception {
private:
const std::string what_;
public:
AttributeError(const std::string& name, const std::string& problem) :
what_("Class " + name + ": " + problem) {}
~AttributeError() throw() {}
virtual const char* what() const throw() { return what_.c_str(); }
};
/** Special "magic number" passed into MATLAB constructor to indicate creating /** Special "magic number" passed into MATLAB constructor to indicate creating
* a MATLAB object from a shared_ptr allocated in C++ * a MATLAB object from a shared_ptr allocated in C++