diff --git a/wrap/FullyOverloadedFunction.cpp b/wrap/FullyOverloadedFunction.cpp new file mode 100644 index 000000000..9c354a429 --- /dev/null +++ b/wrap/FullyOverloadedFunction.cpp @@ -0,0 +1,35 @@ +#include "FullyOverloadedFunction.h" + +using namespace std; + +namespace wrap { +const std::array FullyOverloadedFunction::pythonKeywords{ + {"print", "lambda"}}; + +/* ************************************************************************* */ +std::string FullyOverloadedFunction::pyx_functionCall( + const std::string& caller, + const std::string& funcName, size_t iOverload) const { + + string ret; + if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr && + returnVals_[iOverload].type1.isNonBasicType()) { + ret = returnVals_[iOverload].type1.shared_pxd_class_in_pyx() + "(new " + + returnVals_[iOverload].type1.pxd_class_in_pyx() + "("; + } + + // actual function call ... + if (!caller.empty()) ret += caller + "."; + ret += funcName; + if (templateArgValue_) ret += "[" + templateArgValue_->pxd_class_in_pyx() + "]"; + //... with argument list + ret += "(" + argumentList(iOverload).pyx_asParams() + ")"; + + if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr && + returnVals_[iOverload].type1.isNonBasicType()) + ret += "))"; + + return ret; +} + +} \ No newline at end of file diff --git a/wrap/FullyOverloadedFunction.h b/wrap/FullyOverloadedFunction.h index 645b7cf82..87c5169dd 100644 --- a/wrap/FullyOverloadedFunction.h +++ b/wrap/FullyOverloadedFunction.h @@ -19,6 +19,7 @@ #pragma once #include "OverloadedFunction.h" +#include namespace wrap { @@ -116,6 +117,19 @@ public: return first; } + // emit cython pyx function call + std::string pyx_functionCall(const std::string& caller, const std::string& funcName, + size_t iOverload) const; + + /// Cython: Rename functions which names are python keywords + static const std::array pythonKeywords; + static std::string pyRename(const std::string& name) { + if (std::find(pythonKeywords.begin(), pythonKeywords.end(), name) == + pythonKeywords.end()) + return name; + else + return name + "_"; + } }; // Templated checking functions diff --git a/wrap/GlobalFunction.cpp b/wrap/GlobalFunction.cpp index 3f667e2c9..abd0d06a9 100644 --- a/wrap/GlobalFunction.cpp +++ b/wrap/GlobalFunction.cpp @@ -16,11 +16,12 @@ using namespace std; /* ************************************************************************* */ void GlobalFunction::addOverload(const Qualified& overload, - const ArgumentList& args, const ReturnValue& retVal, + const ArgumentList& args, const ReturnValue& retVal, const std::string& _includeFile, boost::optional instName, bool verbose) { FullyOverloadedFunction::addOverload(overload.name(), args, retVal, instName, verbose); overloads.push_back(overload); + includeFile = _includeFile; } /* ************************************************************************* */ @@ -131,6 +132,47 @@ void GlobalFunction::python_wrapper(FileWriter& wrapperFile) const { wrapperFile.oss << "def(\"" << name_ << "\", " << name_ << ");\n"; } +/* ************************************************************************* */ +void GlobalFunction::emit_cython_pxd(FileWriter& file) const { + file.oss << "cdef extern from \"" << includeFile << "\" namespace \"" + << overloads[0].qualifiedNamespaces("::") + << "\":" << endl; + for (size_t i = 0; i < nrOverloads(); ++i) { + file.oss << "\t\t"; + returnVals_[i].emit_cython_pxd(file, ""); + file.oss << pyRename(name_) + " \"" + overloads[0].qualifiedName("::") + + "\"("; + argumentList(i).emit_cython_pxd(file, ""); + file.oss << ")"; + file.oss << "\n"; + } +} + +/* ************************************************************************* */ +void GlobalFunction::emit_cython_pyx(FileWriter& file) const { + string funcName = pyRename(name_); + + // Function definition + file.oss << "def " << funcName; + // modify name of function instantiation as python doesn't allow overloads + // e.g. template funcName(...) --> funcNameA, funcNameB, funcNameC + if (templateArgValue_) file.oss << templateArgValue_->name(); + // funtion arguments + file.oss << "("; + argumentList(0).emit_cython_pyx(file); + file.oss << "):\n"; + + /// Call cython corresponding function and return + string ret = pyx_functionCall("pxd", funcName, 0); + if (!returnVals_[0].isVoid()) { + file.oss << "\tcdef " << returnVals_[0].pyx_returnType() + << " ret = " << ret << "\n"; + file.oss << "\treturn " << returnVals_[0].pyx_casting("ret") << "\n"; + } else { + file.oss << "\t" << ret << "\n"; + } +} + /* ************************************************************************* */ } // \namespace wrap diff --git a/wrap/GlobalFunction.h b/wrap/GlobalFunction.h index b2a582654..c293256fb 100644 --- a/wrap/GlobalFunction.h +++ b/wrap/GlobalFunction.h @@ -28,10 +28,11 @@ namespace wrap { struct GlobalFunction: public FullyOverloadedFunction { std::vector overloads; ///< Stack of qualified names + std::string includeFile; // adds an overloaded version of this function, void addOverload(const Qualified& overload, const ArgumentList& args, - const ReturnValue& retVal, boost::optional instName = + const ReturnValue& retVal, const std::string& _includeFile = "", boost::optional instName = boost::none, bool verbose = false); void verifyArguments(const std::vector& validArgs) const { @@ -50,6 +51,10 @@ struct GlobalFunction: public FullyOverloadedFunction { // emit python wrapper void python_wrapper(FileWriter& wrapperFile) const; + // emit cython wrapper + void emit_cython_pxd(FileWriter& pxdFile) const; + void emit_cython_pyx(FileWriter& pyxFile) const; + private: // Creates a single global function - all in same namespace @@ -67,12 +72,15 @@ struct GlobalFunctionGrammar: public classic::grammar { GlobalFunctions& global_functions_; ///< successful parse will be placed in here std::vector& namespaces_; + std::string& includeFile; /// Construct type grammar and specify where result is placed GlobalFunctionGrammar(GlobalFunctions& global_functions, - std::vector& namespaces) : - global_functions_(global_functions), namespaces_(namespaces) { - } + std::vector& namespaces, + std::string& includeFile) + : global_functions_(global_functions), + namespaces_(namespaces), + includeFile(includeFile) {} /// Definition of type grammar template @@ -101,16 +109,16 @@ struct GlobalFunctionGrammar: public classic::grammar { globalFunctionName_p = lexeme_d[(upper_p | lower_p) >> *(alnum_p | '_')]; // parse a global function - global_function_p = (returnValue_g - >> globalFunctionName_p[assign_a(globalFunction.name_)] - >> argumentList_g >> ';' >> *comments_p) // - [assign_a(globalFunction.namespaces_, self.namespaces_)][bl::bind( + global_function_p = (returnValue_g >> globalFunctionName_p[assign_a( + globalFunction.name_)] >> + argumentList_g >> ';' >> *comments_p) // + [assign_a(globalFunction.namespaces_, self.namespaces_)] // + [bl::bind( &GlobalFunction::addOverload, bl::var(self.global_functions_)[bl::var(globalFunction.name_)], - bl::var(globalFunction), bl::var(args), bl::var(retVal), - boost::none, verbose)] // + bl::var(globalFunction), bl::var(args), bl::var(retVal), bl::var(self.includeFile), + boost::none, verbose)] // [assign_a(retVal, retVal0)][clear_a(globalFunction)][clear_a(args)]; - } classic::rule const& start() const { diff --git a/wrap/Method.cpp b/wrap/Method.cpp index 3a536ad16..5b72ffd32 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -28,17 +28,6 @@ using namespace std; using namespace wrap; -/* ************************************************************************* */ -/// Cython: Rename functions which names are python keywords -static const std::array pythonKeywords{{"print", "lambda"}}; -static std::string pyRename(const std::string& name) { - if (std::find(pythonKeywords.begin(), pythonKeywords.end(), name) == - pythonKeywords.end()) - return name; - else - return name + "_"; -} - /* ************************************************************************* */ bool Method::addOverload(Str name, const ArgumentList& args, const ReturnValue& retVal, bool is_const, diff --git a/wrap/MethodBase.cpp b/wrap/MethodBase.cpp index a88a7abd5..ef169d989 100644 --- a/wrap/MethodBase.cpp +++ b/wrap/MethodBase.cpp @@ -138,28 +138,3 @@ void MethodBase::python_wrapper(FileWriter& wrapperFile, Str className) const { } /* ************************************************************************* */ -std::string MethodBase::pyx_functionCall( - const std::string& caller, - const std::string& funcName, size_t iOverload) const { - - string ret; - if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr && - returnVals_[iOverload].type1.isNonBasicType()) { - ret = returnVals_[iOverload].type1.shared_pxd_class_in_pyx() + "(new " + - returnVals_[iOverload].type1.pxd_class_in_pyx() + "("; - } - - // actual function call ... - ret += caller + "." + funcName; - if (templateArgValue_) ret += "[" + templateArgValue_->pxd_class_in_pyx() + "]"; - //... with argument list - ret += "(" + argumentList(iOverload).pyx_asParams() + ")"; - - if (!returnVals_[iOverload].isPair && !returnVals_[iOverload].type1.isPtr && - returnVals_[iOverload].type1.isNonBasicType()) - ret += "))"; - - return ret; -} - -/* ************************************************************************* */ diff --git a/wrap/MethodBase.h b/wrap/MethodBase.h index f25e4e1fc..ee72a6a53 100644 --- a/wrap/MethodBase.h +++ b/wrap/MethodBase.h @@ -54,10 +54,6 @@ struct MethodBase : public FullyOverloadedFunction { // emit python wrapper void python_wrapper(FileWriter& wrapperFile, Str className) const; - // emit cython pyx function call - std::string pyx_functionCall(const std::string& caller, const std::string& funcName, - size_t iOverload) const; - protected: virtual void proxy_header(FileWriter& proxyFile) const = 0; diff --git a/wrap/Module.cpp b/wrap/Module.cpp index ab28509fa..65620ede5 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -149,7 +149,8 @@ void Module::parseMarkup(const std::string& data) { bl::var(newType), bl::var(currentInclude))]; // Create grammar for global functions - GlobalFunctionGrammar global_function_g(global_functions,namespaces); + GlobalFunctionGrammar global_function_g(global_functions, namespaces, + currentInclude); Rule include_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[push_back_a(includes)] @@ -364,6 +365,11 @@ void Module::emit_cython_pxd(FileWriter& pxdFile) const { } pxdFile.oss << "\n\n"; } + + //... wrap global functions + for(const GlobalFunctions::value_type& p: global_functions) + p.second.emit_cython_pxd(pxdFile); + pxdFile.emit(true); } @@ -387,6 +393,9 @@ void Module::emit_cython_pyx(FileWriter& pyxFile) const { for(const Class& cls: expandedClasses) cls.emit_cython_pyx(pyxFile, expandedClasses); pyxFile.oss << "\n"; + //... wrap global functions + for(const GlobalFunctions::value_type& p: global_functions) + p.second.emit_cython_pyx(pyxFile); pyxFile.emit(true); } diff --git a/wrap/ReturnType.h b/wrap/ReturnType.h index 9378c4adc..2a5a38c49 100644 --- a/wrap/ReturnType.h +++ b/wrap/ReturnType.h @@ -43,7 +43,9 @@ struct ReturnType : public Qualified { throw DependencyMissing(key, "checking return type of " + s); } + /// @param className the actual class name to use when "This" is specified void emit_cython_pxd(FileWriter& file, const std::string& className) const; + std::string pyx_returnType(bool addShared = true) const; std::string pyx_casting(const std::string& var, bool isSharedVar = true) const; diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index f629215ca..42963d001 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -71,6 +71,7 @@ struct ReturnValue { void emit_matlab(FileWriter& proxyFile) const; + /// @param className the actual class name to use when "This" is specified void emit_cython_pxd(FileWriter& file, const std::string& className) const; std::string pyx_returnType() const; std::string pyx_casting(const std::string& var) const;