diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 8e04543e4..749a61707 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -24,7 +24,6 @@ #include // works on Linux GCC #include -#include #include #include "Class.h" @@ -40,18 +39,7 @@ void Class::matlab_proxy(const string& toolboxPath, const string& wrapperName, FileWriter& wrapperFile, vector& functionNames) const { // Create namespace folders - { - using namespace boost::filesystem; - path curPath = toolboxPath; - BOOST_FOREACH(const string& subdir, namespaces) { - curPath /= "+" + subdir; - if(!is_directory(curPath)) - if(exists("+" + subdir)) - throw OutputError("Need to write files to directory " + curPath.string() + ", which already exists as a file but is not a directory"); - else - boost::filesystem::create_directory(curPath); - } - } + createNamespaceStructure(namespaces, toolboxPath); // open destination classFile string classFile = toolboxPath; diff --git a/wrap/GlobalFunction.cpp b/wrap/GlobalFunction.cpp index e20a1f2f2..14bb824d2 100644 --- a/wrap/GlobalFunction.cpp +++ b/wrap/GlobalFunction.cpp @@ -6,9 +6,15 @@ */ #include "GlobalFunction.h" +#include "utilities.h" + +#include +#include namespace wrap { +using namespace std; + /* ************************************************************************* */ void GlobalFunction::addOverload(bool verbose, const std::string& name, const ArgumentList& args, const ReturnValue& retVal, const StrVec& ns_stack) { @@ -19,6 +25,142 @@ void GlobalFunction::addOverload(bool verbose, const std::string& name, this->namespaces.push_back(ns_stack); } +/* ************************************************************************* */ +void GlobalFunction::matlab_proxy(const std::string& toolboxPath, const std::string& wrapperName, + const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, + std::vector& functionNames) const { + + // cluster overloads with same namespace + // create new GlobalFunction structures around namespaces - same namespaces and names are overloads + // map of namespace to global function + typedef map GlobalFunctionMap; + GlobalFunctionMap grouped_functions; + for (size_t i=0; i& functionNames) const { + + // create the folder for the namespace + const StrVec& ns = namespaces.front(); + createNamespaceStructure(ns, toolboxPath); + + // open destination mfunctionFileName + string mfunctionFileName = toolboxPath; + if(!ns.empty()) + mfunctionFileName += "/+" + wrap::qualifiedName("/+", ns); + mfunctionFileName += "/" + name + ".m"; + FileWriter mfunctionFile(mfunctionFileName, verbose_, "%"); + + // get the name of actual matlab object + const string + matlabQualName = qualifiedName(".", ns, name), + matlabUniqueName = qualifiedName("", ns, name), + cppName = qualifiedName("::", ns, name); + + mfunctionFile.oss << "function varargout = " << name << "(varargin)\n"; + + for(size_t overload = 0; overload < argLists.size(); ++overload) { + const ArgumentList& args = argLists[overload]; + const ReturnValue& returnVal = returnVals[overload]; + size_t nrArgs = args.size(); + + const int id = functionNames.size(); + + // Output proxy matlab code + + // check for number of arguments... + mfunctionFile.oss << (overload==0?"":"else") << "if length(varargin) == " << nrArgs; + if (nrArgs>0) mfunctionFile.oss << " && "; + // ...and their types + bool first = true; + for(size_t i=0;i(id); + + // call + wrapperFile.oss << "void " << wrapFunctionName << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n"; + // start + wrapperFile.oss << "{\n"; + + if(returnVal.isPair) + { + if(returnVal.category1 == ReturnValue::CLASS) + wrapperFile.oss << " typedef boost::shared_ptr<" << returnVal.qualifiedType1("::") << "> Shared" << returnVal.type1 << ";"<< endl; + if(returnVal.category2 == ReturnValue::CLASS) + wrapperFile.oss << " typedef boost::shared_ptr<" << returnVal.qualifiedType2("::") << "> Shared" << returnVal.type2 << ";"<< endl; + } + else { + if (returnVal.category1 == ReturnValue::CLASS) + wrapperFile.oss << " typedef boost::shared_ptr<" << returnVal.qualifiedType1("::") << "> Shared" << returnVal.type1 << ";"<< endl; + } + + // check arguments + // NOTE: for static functions, there is no object passed + wrapperFile.oss << " checkArguments(\"" << matlabUniqueName << "\",nargout,nargin," << args.size() << ");\n"; + + // unwrap arguments, see Argument.cpp + args.matlab_unwrap(wrapperFile,0); // We start at 0 because there is no self object + + // call method with default type and wrap result + if (returnVal.type1!="void") + returnVal.wrap_result(cppName+"("+args.names()+")", wrapperFile, typeAttributes); + else + wrapperFile.oss << cppName+"("+args.names()+");\n"; + + // finish + wrapperFile.oss << "}\n"; + + // Add to function list + functionNames.push_back(wrapFunctionName); + } + + mfunctionFile.oss << "else\n"; + mfunctionFile.oss << " error('Arguments do not match any overload of function " << matlabQualName << "');" << endl; + mfunctionFile.oss << "end" << endl; + + // Close file + mfunctionFile.emit(true); +} + /* ************************************************************************* */ diff --git a/wrap/GlobalFunction.h b/wrap/GlobalFunction.h index 0899bbdc9..e281e6a6d 100644 --- a/wrap/GlobalFunction.h +++ b/wrap/GlobalFunction.h @@ -29,10 +29,26 @@ struct GlobalFunction { // Constructor only used in Module GlobalFunction(bool verbose = true) : verbose_(verbose) {} + // Used to reconstruct + GlobalFunction(const std::string& name_, bool verbose = true) + : verbose_(verbose), name(name_) {} + // adds an overloaded version of this function void addOverload(bool verbose, const std::string& name, const ArgumentList& args, const ReturnValue& retVal, const StrVec& ns_stack); + // codegen function called from Module to build the cpp and matlab versions of the function + void matlab_proxy(const std::string& toolboxPath, const std::string& wrapperName, + const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, + std::vector& functionNames) const; + +private: + + // Creates a single global function - all in same namespace + void generateSingleFunction(const std::string& toolboxPath, const std::string& wrapperName, + const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, + std::vector& functionNames) const; + }; } // \namespace wrap diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 757241ca2..35b0d2ff8 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -464,6 +464,11 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co cls.matlab_proxy(toolboxPath, wrapperName, typeAttributes, wrapperFile, functionNames); } + // create matlab files and wrapper code for global functions + BOOST_FOREACH(const GlobalFunctions::value_type& p, global_functions) { + p.second.matlab_proxy(toolboxPath, wrapperName, typeAttributes, wrapperFile, functionNames); + } + // finish wrapper file wrapperFile.oss << "\n"; finish_wrapper(wrapperFile, functionNames); diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index fcef79857..f123a31ac 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -38,6 +38,7 @@ void StaticMethod::addOverload(bool verbose, const std::string& name, this->returnVals.push_back(retVal); } +/* ************************************************************************* */ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const string& cppClassName, const std::string& matlabQualName, diff --git a/wrap/tests/expected/aGlobalFunction.m b/wrap/tests/expected/aGlobalFunction.m new file mode 100644 index 000000000..80d6b1f6b --- /dev/null +++ b/wrap/tests/expected/aGlobalFunction.m @@ -0,0 +1,7 @@ +% automatically generated by wrap +function varargout = aGlobalFunction(varargin) +if length(varargin) == 0 + varargout{1} = geometry_wrapper(40, varargin{:}); +else + error('Arguments do not match any overload of function aGlobalFunction'); +end diff --git a/wrap/tests/expected/geometry_wrapper.cpp b/wrap/tests/expected/geometry_wrapper.cpp index a520803ee..d403073d4 100644 --- a/wrap/tests/expected/geometry_wrapper.cpp +++ b/wrap/tests/expected/geometry_wrapper.cpp @@ -495,6 +495,11 @@ using namespace geometry; out[0] = wrap< Vector >(obj->return_vector2(value)); } +void aGlobalFunction_40(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + checkArguments("aGlobalFunction",nargout,nargin,0); + out[0] = wrap< Vector >(aGlobalFunction()); +} void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { @@ -626,6 +631,9 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[]) case 39: Test_return_vector2_39(nargout, out, nargin-1, in+1); break; + case 40: + aGlobalFunction_40(nargout, out, nargin-1, in+1); + break; } std::cout.rdbuf(outbuf); diff --git a/wrap/tests/expected_namespaces/+ns1/aGlobalFunction.m b/wrap/tests/expected_namespaces/+ns1/aGlobalFunction.m new file mode 100644 index 000000000..fc1e780af --- /dev/null +++ b/wrap/tests/expected_namespaces/+ns1/aGlobalFunction.m @@ -0,0 +1,7 @@ +% automatically generated by wrap +function varargout = aGlobalFunction(varargin) +if length(varargin) == 0 + varargout{1} = testNamespaces_wrapper(22, varargin{:}); +else + error('Arguments do not match any overload of function ns1.aGlobalFunction'); +end diff --git a/wrap/tests/expected_namespaces/+ns2/aGlobalFunction.m b/wrap/tests/expected_namespaces/+ns2/aGlobalFunction.m new file mode 100644 index 000000000..2bdf45dd6 --- /dev/null +++ b/wrap/tests/expected_namespaces/+ns2/aGlobalFunction.m @@ -0,0 +1,7 @@ +% automatically generated by wrap +function varargout = aGlobalFunction(varargin) +if length(varargin) == 0 + varargout{1} = testNamespaces_wrapper(23, varargin{:}); +else + error('Arguments do not match any overload of function ns2.aGlobalFunction'); +end diff --git a/wrap/tests/expected_namespaces/testNamespaces_wrapper.cpp b/wrap/tests/expected_namespaces/testNamespaces_wrapper.cpp index 3eb0b0311..c75c6a388 100644 --- a/wrap/tests/expected_namespaces/testNamespaces_wrapper.cpp +++ b/wrap/tests/expected_namespaces/testNamespaces_wrapper.cpp @@ -332,6 +332,17 @@ void ClassD_deconstructor_21(int nargout, mxArray *out[], int nargin, const mxAr } } +void ns1aGlobalFunction_22(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + checkArguments("ns1aGlobalFunction",nargout,nargin,0); + out[0] = wrap< Vector >(ns1::aGlobalFunction()); +} + +void ns2aGlobalFunction_23(int nargout, mxArray *out[], int nargin, const mxArray *in[]) +{ + checkArguments("ns2aGlobalFunction",nargout,nargin,0); + out[0] = wrap< Vector >(ns2::aGlobalFunction()); +} void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { @@ -409,6 +420,12 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[]) case 21: ClassD_deconstructor_21(nargout, out, nargin-1, in+1); break; + case 22: + ns1aGlobalFunction_22(nargout, out, nargin-1, in+1); + break; + case 23: + ns2aGlobalFunction_23(nargout, out, nargin-1, in+1); + break; } std::cout.rdbuf(outbuf); diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index 2de19f6e4..29fc1891a 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -291,6 +291,7 @@ TEST( wrap, matlab_code_geometry ) { EXPECT(files_equal(epath + "Point2.m" , apath + "Point2.m" )); EXPECT(files_equal(epath + "Point3.m" , apath + "Point3.m" )); EXPECT(files_equal(epath + "Test.m" , apath + "Test.m" )); + EXPECT(files_equal(epath + "aGlobalFunction.m" , apath + "aGlobalFunction.m" )); } /* ************************************************************************* */ diff --git a/wrap/utilities.cpp b/wrap/utilities.cpp index 6eb47c55d..6b6e57094 100644 --- a/wrap/utilities.cpp +++ b/wrap/utilities.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "utilities.h" @@ -137,6 +138,21 @@ string qualifiedName(const string& separator, const vector& names, const return result; } +/* ************************************************************************* */ +void createNamespaceStructure(const std::vector& namespaces, const std::string& toolboxPath) { + using namespace boost::filesystem; + path curPath = toolboxPath; + BOOST_FOREACH(const string& subdir, namespaces) { + curPath /= "+" + subdir; + if(!is_directory(curPath)) { + if(exists("+" + subdir)) + throw OutputError("Need to write files to directory " + curPath.string() + ", which already exists as a file but is not a directory"); + else + boost::filesystem::create_directory(curPath); + } + } +} + /* ************************************************************************* */ } // \namespace wrap diff --git a/wrap/utilities.h b/wrap/utilities.h index 7e28d6793..2eaf5397a 100644 --- a/wrap/utilities.h +++ b/wrap/utilities.h @@ -133,4 +133,7 @@ void generateUsingNamespace(FileWriter& file, const std::vector& us */ std::string qualifiedName(const std::string& separator, const std::vector& names, const std::string& finalName = ""); +/** creates the necessary folders for namespaces, as specified by a namespace stack */ +void createNamespaceStructure(const std::vector& namespaces, const std::string& toolboxPath); + } // \namespace wrap